首页 > 解决方案 > 为 group by 中的每个组创建列

问题描述

假设我有一个表T,其条目如下:

id   | type   | value   | 
-------------------------
1    | A      | 7
1    | B      | 8
2    | A      | 9
2    | B      | 10
3    | A      | 11
3    | B      | 12
1    | C      | 13
2    | C      | 14

对于每种类型,我想要一个不同的列。由于类型的数量是详尽的,我希望枚举所有不同的类型并为每个类型提供相应的列。我想为id表创建一个主键。

因此,所需的输出类似于:

id   | A's value | B's value | C's value
------------------------------------------
1    | 7         | 8         | 13
2    | 9         | 10        | 14
3    | 11        | 12        | NULL

请注意,这是一个简化版本。实际的表T是从一个更大的表派生的,使用group by. 对于每个组,我想要一个单独的专栏。这甚至可能吗?

标签: sqlsnowflake-cloud-data-platform

解决方案


我建议查看 PIVOT 功能:

https://docs.snowflake.com/en/sql-reference/constructs/pivot.html

不过,这个函数的主要障碍是需要预先确定 pivot_column 的值列表。为此,我通常使用 LISTAGG 函数:

https://docs.snowflake.com/en/sql-reference/functions/listagg.html

我在下面包含了一个查询,向您展示如何构建该字符串,并且在 Python 之类的脚本甚至存储过程中一起执行此操作应该相当简单(构建 pivot_column,构建聚合/数据透视命令,执行聚合/枢轴命令)。

我希望这会有所帮助...丰富

CREATE OR REPLACE TABLE monthly_sales(
    empid   INT, 
    amount  INT, 
    month   TEXT)
AS SELECT * FROM VALUES
    (1, 10000, 'JAN'),
    (1, 400, 'JAN'),
    (2, 4500, 'JAN'),
    (2, 35000, 'JAN'),
    (1, 5000, 'FEB'),
    (1, 3000, 'FEB'),
    (2, 200, 'FEB'),
    (2, 90500, 'FEB'),
    (1, 6000, 'MAR'),
    (1, 5000, 'MAR'),
    (2, 2500, 'MAR'),
    (2, 9500, 'MAR'),
    (1, 8000, 'APR'),
    (1, 10000, 'APR'),
    (2, 800, 'APR'),
    (2, 4500, 'APR');


SELECT * 
FROM monthly_sales
    PIVOT(SUM(amount) 
    FOR month IN ('JAN', 'FEB', 'MAR', 'APR'))
    AS p
ORDER BY empid;

SELECT LISTAGG( DISTINCT  ''''||month||'''',  ', ' ) 
FROM monthly_sales;

推荐阅读