我有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
所需输出(仅来自A& 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
到目前为止SQL SQL Fiddle:
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
我写的查询来自B& C并计算出现次数。但是如果密钥没有出现在B或C中,它就不会出现在输出中(例如输出中的id = 2)。如何从表A&表中开始我的选择?加入/联盟B& C获得所需的输出
答案 0 :(得分:4)
如果查询涉及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);
您需要考虑a_id
和/或a
中某些b
根本不存在的可能性。 count()
永远不会返回NULL
,但是LEFT JOIN
面对的是一种冷漠的感觉,但仍会留下NULL
个缺失行的值。您必须为NULL
做准备。使用 COALESCE()
。
或两个表中的UNION ALL 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);
可能慢一些。但仍然比目前提出的解决方案更快。你可以没有COALESCE()
但仍然没有任何行。在这种情况下,您可能会偶尔获得NULL
的{{1}}值。
答案 1 :(得分:3)
另一种选择:
SELECT
a.id,
(SELECT COUNT(*) FROM b WHERE b.a_id = a.id) +
(SELECT COUNT(*) FROM c WHERE c.a_id = a.id)
FROM
a
答案 2 :(得分:2)
将左连接与子查询一起使用:
SELECT a.id, COUNT(x.id)
FROM a
LEFT JOIN (
SELECT id, a_id FROM b
UNION ALL
SELECT id, a_id FROM c
) x ON (a.id = x.a_id)
GROUP BY a.id;