我有一个包含许多不同产品的大型数据集。在小范围内,它看起来像这样:
产品 | 月 | 金额 |
---|---|---|
AA | 1 | 100 |
AA | 1 | 150 |
AA | 2 | 200 |
AA | 2 | 120 |
BB | 2 | 180 |
BB | 2 | 220 |
抄送 | 3 | 80 |
我想以不同的顺序获取信息。写入与“产品”列中不同的值一样多的新列,然后用每月的金额总和填充它。它看起来像这样:
月 | AA | BB | 抄送 |
---|---|---|---|
1 | 250 | 不适用 | 不适用 |
2 | 320 | 400 | 不适用 |
3 | 不适用 | 不适用 | 80 |
重要的是对表格进行透视,这是我遇到的主要问题。我看到了类似的问题,但所有问题都已通过 PIVOT 函数解决,但我在 DBeaver 中使用 Postgres 数据库执行此操作,但它没有 PIVOT 函数:
SELECT *
FROM (
SELECT product, month, amount
FROM ventas
) AS SourceTable
PIVOT (
SUM(amount)
FOR month IN ([1], [2], [3])
) AS PivotTable;
SQL 错误 [42601]:错误:“PIVOT”处或附近的语法错误 位置:95
我尝试过不同的方法但没有成功。 我无法写出查询中所有产品的名称,因为太多了!
为了您的方便,这里有一个测试设置:
CREATE TABLE ventas (
product VARCHAR(50),
month INT,
amount INT
);
INSERT INTO ventas (product, month, amount) VALUES
('AA', 1, 100),
('AA', 1, 150),
('AA', 2, 200),
('AA', 2, 120),
('BB', 2, 180),
('BB', 2, 220),
('CC', 3, 80),
如果您确实需要单独的输出列,唯一合理的方法是两步流程:
如果您不熟悉
crosstab()
功能,请先阅读以下内容:
-- generate crosstab() query
SELECT format(
$f$ -- begin dynamic query string
SELECT * FROM crosstab(
$q$
SELECT month, product, sum(amount)
FROM ventas
GROUP BY 1, 2
ORDER BY 1, 2
$q$
, $c$VALUES (%s)$c$
) AS ct(month int, %s);
$f$ -- end dynamic query string
, string_agg(quote_literal(sub.product), '), (')
, string_agg(quote_ident (sub.product), ' int, ') || ' int'
)
FROM (SELECT DISTINCT product FROM ventas ORDER BY 1) sub;
这会生成以下形式的查询:
SELECT * FROM crosstab(
$q$
SELECT month, product, sum(amount)
FROM ventas
GROUP BY 1, 2
ORDER BY 1, 2
$q$
, $c$VALUES ('AA'), ('BB'), ('CC')$c$
) AS ct(month int, "AA" int, "BB" int, "CC" int);
...然后执行。
密切相关,有更多解释和选项: