我每月都有时间序列数据,我想按月分组每个ID的值,然后将月份名称作为列而不是行。
+----+------------+-------+-------+
| id | extra_info | month | value |
+----+------------+-------+-------+
| 1 | abc | jan | 10 |
| 1 | abc | feb | 20 |
| 2 | def | jan | 10 |
| 2 | def | feb | 5 |
| 1 | abc | jan | 15 |
| 3 | ghi | mar | 15 |
+----+------------+-----+-----+-----+
| id | extra_info | jan | feb | mar |
+----+------------+-----+-----+-----+
| 1 | abc | 25 | 20 | 0 |
| 2 | def | 10 | 5 | 0 |
| 3 | ghi | 0 | 0 | 15 |
我可以轻松按月分组,总结价值观。这让我:
-----------------------------------
| id | extra_info | month | value |
+----+------------+-------+-------+
| 1 | abc | jan | 25 |
| 1 | abc | feb | 20 |
| 2 | def | jan | 10 |
| 2 | def | feb | 5 |
| 3 | ghi | mar | 15 |
但我现在需要那些月作为列名。不知道从哪里开始。
非常感谢SQL大师的任何想法!
答案 0 :(得分:6)
您可以使用带有CASE
表达式的聚合函数将行转换为列:
select id,
extra_info,
sum(case when month = 'jan' then value else 0 end) jan,
sum(case when month = 'feb' then value else 0 end) feb,
sum(case when month = 'mar' then value else 0 end) mar,
sum(case when month = 'apr' then value else 0 end) apr,
sum(case when month = 'may' then value else 0 end) may,
sum(case when month = 'jun' then value else 0 end) jun,
sum(case when month = 'jul' then value else 0 end) jul,
sum(case when month = 'aug' then value else 0 end) aug,
sum(case when month = 'sep' then value else 0 end) sep,
sum(case when month = 'oct' then value else 0 end) oct,
sum(case when month = 'nov' then value else 0 end) nov,
sum(case when month = 'dec' then value else 0 end) "dec"
from yt
group by id, extra_info
答案 1 :(得分:2)
我会使用crosstab()
。如果您还没有安装附加模块tablefunc
:
CREATE EXTENSION tablefunc
基础知识:
PostgreSQL Crosstab Query
如何处理额外的列:
Pivot on Multiple Columns using Tablefunc
高级用法:
Dynamic alternative to pivot with CASE and GROUP BY
CREATE TEMP TABLE tbl
(id int, extra_info varchar(3), month date, value int);
INSERT INTO tbl (id, extra_info, month, value)
VALUES
(1, 'abc', '2012-01-01', 10),
(1, 'abc', '2012-02-01', 20),
(2, 'def', '2012-01-01', 10),
(2, 'def', '2012-02-01', 5),
(1, 'abc', '2012-01-01', 15),
(3, 'ghi', '2012-03-01', 15);
我在基表中使用实际的date
,因为我假设只是为了简化你的问题而隐藏它。但只有月份名称,ORDER BY
就没有了。
SELECT * FROM crosstab(
$$SELECT id, extra_info, to_char(month, 'mon'), sum(value) AS value
FROM tbl
GROUP BY 1,2,month
ORDER BY 1,2,month$$
,$$VALUES
('jan'::text), ('feb'), ('mar'), ('apr'), ('may'), ('jun')
, ('jul'), ('aug'), ('sep'), ('oct'), ('nov'), ('dec')$$
)
AS ct (id int, extra text
, jan int, feb int, mar int, apr int, may int, jun int
, jul int, aug int, sep int, oct int, nov int, dec int);
结果:
id | extra | jan | feb | mar | apr | may | jun | jul | aug | sep | oct | nov | dec
----+-------+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----
1 | abc | 25 | 20 | | | | | | | | | |
2 | def | 10 | 5 | | | | | | | | | |
3 | ghi | | | 15 | | | | | | | | |
安装tablefunc模块需要一些开销和一些学习,但结果查询更快,更短,更通用。