cli*_*ick 5 sql postgresql aggregate-functions left-join correlated-subquery
我有3个表,表B和C通过外键引用表A. 我想在PostgreSQL中编写一个查询来获取A中的所有ID以及它们在B&C中的总出现次数.
a | b | c
-----------------------------------
id | txt | id | a_id | id | a_id
---+---- | ---+----- | ---+------
1 | a | 1 | 1 | 1 | 3
2 | b | 2 | 1 | 2 | 4
3 | c | 3 | 3 | 3 | 4
4 | d | 4 | 4 | 4 | 4
Run Code Online (Sandbox Code Playgroud)
所需输出(只是A中的id和B&C中的总数):
id | Count
---+-------
1 | 2 -- twice in B
2 | 0 -- occurs nowhere
3 | 2 -- once in B & once in C
4 | 4 -- once in B & thrice in C
Run Code Online (Sandbox Code Playgroud)
SQL到目前为止SQL小提琴:
SELECT a_id, COUNT(a_id)
FROM
( SELECT a_id FROM b
UNION ALL
SELECT a_id FROM c
) AS union_table
GROUP BY a_id
Run Code Online (Sandbox Code Playgroud)
我写的查询从B&C获取并计算出现次数.但是如果密钥没有出现在B或C中,它就不会出现在输出中(例如输出中的id = 2).如何从表A和join/union B&C开始我的选择以获得所需的输出
如果查询涉及大部分b和/或c先聚合再连接效率更高。
我希望这两个变体会快得多:
SELECT a.id,
,COALESCE(b.ct, 0) + COALESCE(c.ct, 0) AS bc_ct
FROM a
LEFT JOIN (SELECT a_id, count(*) AS ct FROM b GROUP BY 1) b USING (a_id)
LEFT JOIN (SELECT a_id, count(*) AS ct FROM c GROUP BY 1) c USING (a_id);
Run Code Online (Sandbox Code Playgroud)
您需要考虑a_id在a和/或中根本不存在某些内容的可能性b。count()永远不会返回NULL,但是面对LEFT JOIN,这是冷酷的安慰,NULL尽管如此,这仍然会给您留下缺失行的值。你必须为NULL. 使用COALESCE().
或者a_id从两个表中联合所有,聚合,然后加入:
SELECT a.id
,COALESCE(ct.bc_ct, 0) AS bc_ct
FROM a
LEFT JOIN (
SELECT a_id, count(*) AS bc_ct
FROM (
SELECT a_id FROM b
UNION ALL
SELECT a_id FROM c
) bc
GROUP BY 1
) ct USING (a_id);
Run Code Online (Sandbox Code Playgroud)
可能比较慢。但仍然比目前提出的解决方案更快。而且你可以不做COALESCE()并且仍然不会丢失任何行。在这种情况下,您可能会偶尔获得 的NULL值bc_ct。
| 归档时间: |
|
| 查看次数: |
2514 次 |
| 最近记录: |