内容简介:做过数据清洗ETL工作的都知道,行列转换是一个常见的数据整理需求。在不同的编程语言中有不同的实现方法,比如SQL中使用case+group,或者Power BI的M语言中用拖放组件实现。今天正好需要在PostgreSQL中处理一个数据行列转换,就把这个方法记录下来。首先明确一下啥叫表1
做过数据清洗ETL工作的都知道,行列转换是一个常见的数据整理需求。在不同的编程语言中有不同的实现方法,比如 SQL 中使用case+group,或者Power BI的M语言中用拖放组件实现。今天正好需要在PostgreSQL中处理一个数据行列转换,就把这个方法记录下来。
首先明确一下啥叫 行列转换 ,因为这个叫法也不是很统一,有的地方叫转置,有的地方叫透视,不一而足。我们就以下表为例,定义如下:
- 从表1这种变成表2这种,叫 透视(pivot)
- 反之叫 逆透视(unpivot)
表1
| 项目 | 月份 | 金额 |
|---|---|---|
| A | 1 | 10 |
| A | 2 | 20 |
| A | 2 | 30 |
| B | 1 | 30 |
表2
| 项目 | 1月 | 2月 |
|---|---|---|
| A | 10 | 50 |
| B | 30 |
构造样本数据
构造一个表以 行 格式保存数据
drop table if exists demo.tf_pivot;
create table demo.tf_pivot (
city text,
year integer,
month integer,
income integer
);
insert into demo.tf_pivot values('a', 2018, 1, 1);
insert into demo.tf_pivot values('a', 2018, 2, 1);
insert into demo.tf_pivot values('a', 2018, 3, 1);
insert into demo.tf_pivot values('a', 2018, 4, 1);
insert into demo.tf_pivot values('a', 2019, 1, 2);
insert into demo.tf_pivot values('a', 2019, 2, 2);
insert into demo.tf_pivot values('a', 2019, 3, 2);
insert into demo.tf_pivot values('a', 2019, 4, 2);
insert into demo.tf_pivot values('b', 2018, 1, 3);
insert into demo.tf_pivot values('b', 2018, 2, 3);
insert into demo.tf_pivot values('b', 2018, 3, 3);
insert into demo.tf_pivot values('b', 2018, 4, 3);
insert into demo.tf_pivot values('b', 2019, 1, 4);
insert into demo.tf_pivot values('b', 2019, 2, 4);
insert into demo.tf_pivot values('b', 2019, 3, 4);
insert into demo.tf_pivot values('b', 2019, 4, 4);
复制代码
构造一个表以 列 格式保存数据
drop table if exists demo.tf_unpivot;
create table demo.tf_unpivot(
city text,
year int,
m01 int,
m02 int,
m03 int,
m04 int
);
insert into demo.tf_unpivot values('a', 2018, 1,2,3,4);
insert into demo.tf_unpivot values('a', 2019, 10,20,30,40);
insert into demo.tf_unpivot values('b', 2018, 100,200,300,400);
复制代码
透视Pivot
CASE语法
首先展示一下传统的case when语法。在PostgreSQL中,还提供了一个filter语法(简化case when)
-- case when , 在PG中可以使用filter select city, sum(income) filter (where year=2018) as "2018", sum(income) filter (where year=2019) as "2019" from demo.tf_pivot group by city order by city; -- 结果 city | 2018 | 2019 ------+------+------ a | 4 | 8 b | 12 | 16 (2 rows) 复制代码
CROSSTAB语法
在PostgreSQL中,如果安装了tablefunc扩展,就可以使用crosstab()函数来简化pivot操作。crosstab()提供了多个版本,这里仅演示最基础的版本 crosstab(sql text, sql text)。
基础用法
crosstab()透视操作简单直接,关键点说明如下
- 第一个参数,带有按X,Y汇总的SQL子句,返回X,Y,Value格式的数据集;
- 第二个参数,SQL子句,返回用于水平表头中透视内容的所有值;
- 使用AS子句明确指定返回的每一个字段名称和类型;
代码如下
--
select * from crosstab(
-- 基础查询,返回X,Y,V格式的数据集
'select city,year,sum(income)
from demo.tf_pivot
group by city,year
order by 1, 2',
-- 产生水平表头的查询
'select distinct year from demo.tf_pivot order by 1')
-- 因为crosstab()返回的结果是不能动态确定的,所以需要指定字段名称和类型
as ("city" text,
"y2018" int, -- 这里的类型是字段内容的类型,不是表头
"y2019" int);
复制代码
结果如下
city | y2018 | y2019 ------+-------+------- a | 4 | 8 b | 12 | 16 (2 rows) 复制代码
多维表格的用法
在实际应用中,可能我们需要的最终结果包括多维数据,比如下面这种,行上面有两个维度,分别是city和year,然后对month进行透视。(这个结果和我们构造的样例表demo.tf_unpivot是一样的)
city | year | m01 | m02 | m03 | m04 ------+------+-----+-----+-----+----- a | 2018 | 1 | 1 | 1 | 1 a | 2019 | 2 | 2 | 2 | 2 b | 2018 | 3 | 3 | 3 | 3 b | 2019 | 4 | 4 | 4 | 4 (4 rows) 复制代码
因为原生crosstab仅能支持X,Y两个维度,所以我们设计一个取巧算法来达到目的
- 在X上构造一个由多个字段构成的字段;
- crosstab透视;
- 使用split_part()函数把组合字段拆分为多个结果字段;
--
select
-- 把拼接字段进行拆分
split_part(city_year, '~', 1) as city,
split_part(city_year, '~', 2)::int as year,
m01,m02,m03,m04
from crosstab(
-- 把多个字段拼接为一个,然后执行聚合操作
'select city || ''~'' || year, month, sum(income)
from demo.tf_pivot
group by city || ''~'' || year, month
order by 1,2,3',
--
'select distinct month from demo.tf_pivot order by 1')
as ("city_year" text, -- 结果集中指定拼接字段类型为text
"m01" int,
"m02" int,
"m03" int,
"m04" int);
复制代码
逆透视Unpivot
PostgreSQL没有提供函数来实现unpivot操作,不过我们可以使用PG提供的几个高级功能来间接实现需求。需要用到的函数和语法包括:
- row_to_json() 把行数据转换为json串;
- json_each_text() 把最外层的json对象转换成Key/Value,每个对象一行;
- lateral 独立子查询内支持JOIN子查询外面的表(这个还没有搞太明白 :-D)
原始数据如下
select * from demo.tf_unpivot; city | year | m01 | m02 | m03 | m04 ------+------+-----+-----+-----+----- a | 2018 | 1 | 2 | 3 | 4 a | 2019 | 10 | 20 | 30 | 40 b | 2018 | 100 | 200 | 300 | 400 (3 rows) 复制代码
代码如下
-- select r.city, r.year, key as month_str, substr(key, 2)::int as month_int, -- 把 m01 转换成 1 value::int as income from (select city, year, row_to_json(t.*) as line from demo.tf_unpivot t) as r join lateral json_each_text(r.line) on (key ~* '^m[0-9]+'); 复制代码
结果如下
city | year | month_str | month_int | income ------+------+-----------+-----------+-------- a | 2018 | m01 | 1 | 1 a | 2018 | m02 | 2 | 2 a | 2018 | m03 | 3 | 3 a | 2018 | m04 | 4 | 4 a | 2019 | m01 | 1 | 10 a | 2019 | m02 | 2 | 20 a | 2019 | m03 | 3 | 30 a | 2019 | m04 | 4 | 40 b | 2018 | m01 | 1 | 100 b | 2018 | m02 | 2 | 200 b | 2018 | m03 | 3 | 300 b | 2018 | m04 | 4 | 400 (12 rows) 复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- pandas DataFrame索引行列
- Maze勒索软件正式加入披露数据的行列
- 基于行列式点过程的推荐多样性提升算法
- 媒体称聊天宝团队解散,罗永浩一周前已退出股东行列
- Hasor 4.1.10 发布,满满干货:动态数据源、报错定位到行列、权限控制
- JavaScript进阶系列-类型转换、隐式类型转换
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Python机器学习
[美] Michael Bowles / 沙嬴、李鹏 / 人民邮电出版社 / 2016-12 / 69.00元
在学习和研究机器学习的时候,面临令人眼花缭乱的算法,机器学习新手往往会不知 所措。本书从算法和Python 语言实现的角度,帮助读者认识机器学习。 书专注于两类核心的“算法族”,即惩罚线性回归和集成方法,并通过代码实例来 展示所讨论的算法的使用原则。全书共分为7 章,详细讨论了预测模型的两类核心算法、预测模型的构建、惩罚线性回归和集成方法的具体应用和实现。 本书主要针对想提......一起来看看 《Python机器学习》 这本书的介绍吧!