我在
ProductCategorySales
中有一张表 Vertica
具有以下数据
Product, Month, Year, Category1Sales, Category2Sales
P001, 2, 2019, 150, 231
P001, 4, 2022, 120, 52
P002, 1, 2023, 97, 328
P003, 7, 2018, 46, 157
我需要查询此表以形成如下结果集。
Product, 2_2019_Cateogory1Sales, 2_2019_Category2Sales, 4_2022_Category1Sales, 4_2022_Category2Sales, 1_2023_Category1Sales, 1_2023_Category2Sales, 7_2018_Category1Sales, 7_2018_Category2Sales
P001, 150, 231, 120,52,0,0,0,0
P002, 0,0,0,0,97,328,0,0
P003, 0,0,0,0,0,0,46,157
所以基本上,月份和年份被旋转以与 Category1Sales 和 Category2Sales 连接,使用下划线形成列,并将分组应用于产品,这将导致每个产品只有一行。
这里要注意的一件事是给定产品可能有任何月份,所以我不能写 switch case 语句,我的数据透视查询需要是动态的。
有人可以帮我吗?
正如@minatverma 所指出的:小心你的愿望——你最终可能会得到一份 97 列的报告,持续了 4 年!
话虽如此: 您需要一个“标签”,即报告中的列名称,每个类别、月份和年份的组合。
所以我先垂直化你的输入;添加一个标签列
lbl
,它可以包含例如“sls_1_2023_cat1”,然后 UNION SELECT 输入的其余部分,首先返回类别 1 销售额,然后在一个 sales
列中返回类别 2 销售额。这就是CREATE TABLE
步骤。
然后,我使用一个匿名代码块——
DO $$
和最后的$$
之间的位(使用Vertica的前端vsql
来运行脚本,因为许多前端将两个双美元之间的文本拆分成单个块发送到数据库,这是行不通的)。
在那个块中,我创建了一个本地临时表(因为块不能返回结果表)。我开始构建一个包含将要修复的内容的 SQL 语句,然后,对于每个不同的值,对于我找到的
lbl
,我生成一个表达式,例如:
NVL(MAX(CASE lbl WHEN '1_2023_cat1' THEN sales END),0) AS sls_1_2023_cat1
,
并将其连接到已经构建的 sql 语句,并以硬连接的
FROM
和 GROUP BY
子句结束。
然后,我执行我构建的 sql 语句,并且在代码块之后,立即
SELECT * FROM pivot_out
。在同一个会话中,因为临时表一旦注销就消失了。
创建垂直表:
DROP TABLE IF EXISTS vert;
CREATE TABLE vert AS
WITH
indata(Product,Month,Year,Category1Sales,Category2Sales) AS (
SELECT 'P001',2,2019,150,231
UNION ALL SELECT 'P001',4,2022,120,52
UNION ALL SELECT 'P002',1,2023,97,328
UNION ALL SELECT 'P003',7,2018,46,157
)
SELECT
product
, "Month"::VARCHAR(2)||'_'||"Year"::VARCHAR(4)||'_cat1' AS lbl
, Category1Sales AS sales
FROM indata
UNION ALL
SELECT
product
, "Month"::VARCHAR(2)||'_'||"Year"::VARCHAR(4)||'_cat2' AS lbl
, Category2Sales AS sales
FROM indata
ORDER BY 1,2;
旋转:
DO $$
DECLARE
sq VARCHAR;
c VARCHAR;
BEGIN
sq:= CHR(10)||'CREATE LOCAL TEMPORARY TABLE pivot_out ON COMMIT PRESERVE ROWS A
FOR c IN EXECUTE
'SELECT DISTINCT lbl FROM vert ORDER BY 1' LOOP
sq := sq||CHR(10)||', NVL(MAX(CASE lbl WHEN '||QUOTE_LITERAL(c)||' THEN sales
END LOOP;
sq := sq ||CHR(10)||'FROM vert GROUP BY product';
-- vv test output ...
RAISE NOTICE '
*** Running this Query *** %',sq;
-- ^^ test output ...
EXECUTE sq;
END;
$$;
SELECT * FROM pivot_out;
结果:
产品 | sales_1_2023_cat1 | sales_1_2023_cat2 | sales_2_2019_cat1 | sales_2_2019_cat2 | sales_4_2022_cat1 | sales_4_2022_cat2 | sales_7_2018_cat1 | sales_7_2018_cat2 |
---|---|---|---|---|---|---|---|---|
P001 | 0 | 0 | 150 | 231 | 120 | 52 | 0 | 0 |
P002 | 97 | 328 | 0 | 0 | 0 | 0 | 0 | 0 |
P003 | 0 | 0 | 0 | 0 | 0 | 0 | 46 | 157 |