继结合 array_agg 和 unnest之后,给定以下数据:
key | a | b | c
------------------
1 | 0 | 1 | {1,2}
1 | 1 | 2 | {3}
1 | -1 | 3 | {2}
1 | 2 | 4 | {}
执行此查询:
SELECT
d.key,
min(d.a) AS a,
sum(d.b) AS b,
array_agg(DISTINCT x.c) AS c
FROM data AS d
CROSS JOIN LATERAL unnest(d.c) AS x(c)
GROUP BY d.key
给出了意想不到的结果:
key | a | b | c
------------------
1 | -1 | 7 | {1,2,3}
这里发生了什么,以及如何获得正确的总和?
答案表现
根据我的实际数据(16642 行、1942 个键、6 个聚合),我得到了每个建议解决方案的这些成本估算。
- a_horse_with_no_name选项 1:
1761.12..49370.52
- a_horse_with_no_name选项 2:
0.57..89214.72
- 欧文·布兰德施泰特:
1761.12..49370.61
取消嵌套为 (key = 1, a = 0, b = 1) 生成 2 行,并且交叉连接删除具有空数组的行。
因此,您的 group by 对以下集合进行操作:
一种解决方案是组合两个分组查询,每个查询分组不同级别:
另一种方法是仅在聚合中包含每个“未嵌套”组的“第一行”:
with ordinality
返回原始数组中未嵌套元素的位置。对于具有空数组的行,它将为空。您的查询的一个问题是
CROSS JOIN
消除了unnest()
不产生行的行(发生在空数组中{}
)。你可以用 来解决这个
LEFT JOIN .. ON true
问题,但另一个问题是行在unnest()
返回多行的地方相乘(发生在{1,2}
)。这就是你得到
7
总和的方式:1 + 1 + 2 + 3
。加入两个单独的子查询可能是最简单/最快的:
普通连接有效,因为两个子查询都按同一列分组 - 并且只要
key
是NOT NULL
。db<>在这里摆弄
有关的: