PostgreSQL行转列实现求助:将指定数据集转为宽表
实现PostgreSQL行转列的两种实用方法
嗨,针对你这个行转列的需求,在PostgreSQL里有两种很靠谱的实现方式,我给你详细拆解说明:
方法一:条件聚合(通用SQL方案)
这种方法不需要依赖任何扩展,几乎所有SQL数据库都支持,逻辑直观易懂,适合简单的行转列场景:
WITH data AS ( SELECT * FROM ( VALUES ('2018-08-09'::date,'cancel',35), ('2018-08-09'::date,'sum',25), ('2018-08-09'::date,'count',10) ) AS v(date, type, number) ) SELECT date, MAX(CASE WHEN type = 'cancel' THEN number END) AS cancel, MAX(CASE WHEN type = 'sum' THEN number END) AS sum, MAX(CASE WHEN type = 'count' THEN number END) AS count FROM data GROUP BY date;
逻辑说明:
- 用
CASE语句针对每种type筛选出对应的number值; - 因为每个
date + type组合只有一条数据,用MAX/MIN/SUM聚合都可以,这里用MAX只是为了把筛选后的值聚合到同一行; - 最后按
date分组,就能得到你想要的列转行结果。
方法二:使用PostgreSQL专属的crosstab函数(高性能方案)
如果要处理大数据量的行转列,PostgreSQL的tablefunc扩展提供的crosstab函数性能会更优,步骤如下:
首先需要启用tablefunc扩展(只需要执行一次):
CREATE EXTENSION IF NOT EXISTS tablefunc;
然后编写行转列查询:
WITH data AS ( SELECT * FROM ( VALUES ('2018-08-09'::date,'cancel',35), ('2018-08-09'::date,'sum',25), ('2018-08-09'::date,'count',10) ) AS v(date, type, number) ) SELECT * FROM crosstab( -- 源查询:必须按分组列(date)和行标识列(type)排序 'SELECT date, type, number FROM data ORDER BY 1,2', -- 指定要转成列的type值列表 'SELECT unnest(''{"cancel","sum","count"}''::text[])' ) AS ct(date date, cancel int, sum int, count int);
逻辑说明:
- 第一个参数是源数据的查询语句,必须按分组列和行标识列排序,保证数据顺序正确;
- 第二个参数定义了要转成列的所有
type值; - 最后
AS ct(...)部分需要明确指定结果集的列名和数据类型,要和第二个参数的顺序一一对应。
两种方法最终都会输出你想要的结果:
| date | cancel | sum | count |
|---|---|---|---|
| 2018-08-09 | 35 | 25 | 10 |
内容的提问来源于stack exchange,提问作者melik
相关产品推荐
相关产品推荐

