【发布时间】:2023-03-12 14:20:01
【问题描述】:
简介
在本问答中,我们将探讨在使用 PostgreSQL 的同一查询中使用 window functions 和 grouping sets。读者应该熟悉这两个概念才能充分利用这篇文章。 Thisfiddle 可用于跟随。
数据
下表包含一些事务。对于每笔交易,我们都有客户、交易发生的城市以及交付给客户的商品数量。
CREATE TABLE transactions (customer TEXT, city TEXT, units INT);
INSERT INTO transactions VALUES ('Bob', 'Manchester', 10),
('Chuck', 'Manchester', 20),
('Bob', 'Concord', 10),
('Tim', 'Manchester', 15),
('Jane', 'Derry', 10),
('Tim', 'Derry', 15),
('Tim', 'Concord', 20),
('Bob', 'Manchester', 20),
('Chuck', 'Concord', 10);
期望的结果
我希望能够生成一份报告,其中包含对“this 行表示所有交易的比例”或“this 此客户的所有交易”。我也希望能够回答所有这些可能的问题。使用这种报告,我们可以简单地查看每一行并提取有关其与整个报告或特定数据切片的关系的信息。
第一次尝试
我们可以尝试通过使用具有不同 GROUP BY 子句的多个查询来创建这样的报告,然后将它们与 UNION ALL 联合起来,或者我们可以尝试以下操作:
-- Incorrect results
SELECT customer
, city
, SUM(units) AS "units"
, ROUND( 100 * SUM(units) / SUM(SUM(units)) OVER () , 2) AS "to report"
, ROUND( 100 * SUM(units) / SUM(SUM(units)) OVER (PARTITION BY customer) , 2) AS "to customer"
, ROUND( 100 * SUM(units) / SUM(SUM(units)) OVER (PARTITION BY city) , 2) AS "to city"
FROM transactions
GROUP BY CUBE(customer, city)
这里我们在GROUP BY 子句中使用CUBE,它将生成与客户和城市列的所有可能组合相对应的分组。比率的分子是对应于该行的单位总数的聚合。请注意,它对于所有比率都是相同的,并且它包含用作“单位”列的表达式,即SUM(units)。计算分母更复杂,因为我们需要一个窗口函数来计算所需切片的总单位数,即特定客户或城市的总数或整个报告的总数。
不正确的结果
很遗憾,上述查询产生的比率不正确。例如,第一行有 10 个单位,占总数的 7.7% (130),Bob (40) 占总数的 25%,Concord (40) 占总数的 25%,但结果显示低于正确比率在所有情况下。另一个例子是“客户”和“城市”都是NULL的行,这里的“单位”列是130,但计算出的“报告”比率是25%。显然,比率列中的分母是错误的。我们怎样才能得到想要的结果?
| customer | city | units | to report | to customer | to city |
|---|---|---|---|---|---|
| Bob | Concord | 10 | 1.92 | 12.50 | 12.50 |
| Bob | Manchester | 30 | 5.77 | 37.50 | 23.08 |
| Bob | null | 40 | 7.69 | 50.00 | 15.38 |
| Chuck | Concord | 10 | 1.92 | 16.67 | 12.50 |
| Chuck | Manchester | 20 | 3.85 | 33.33 | 15.38 |
| Chuck | null | 30 | 5.77 | 50.00 | 11.54 |
| Jane | Derry | 10 | 1.92 | 50.00 | 20.00 |
| Jane | null | 10 | 1.92 | 50.00 | 3.85 |
| Tim | Concord | 20 | 3.85 | 20.00 | 25.00 |
| Tim | Derry | 15 | 2.88 | 15.00 | 30.00 |
| Tim | null | 50 | 9.62 | 50.00 | 19.23 |
| Tim | Manchester | 15 | 2.88 | 15.00 | 11.54 |
| null | null | 130 | 25.00 | 50.00 | 50.00 |
| null | Manchester | 65 | 12.50 | 25.00 | 50.00 |
| null | Derry | 25 | 4.81 | 9.62 | 50.00 |
| null | Concord | 40 | 7.69 | 15.38 | 50.00 |
【问题讨论】:
标签: sql postgresql group-by window-functions