如何在 vertica 中旋转结果集

问题描述 投票:0回答:1

我在

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 语句,我的数据透视查询需要是动态的。

有人可以帮我吗?

vertica
1个回答
0
投票

正如@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
© www.soinside.com 2019 - 2024. All rights reserved.