sql - 从多个表中获取外键的计数

标签 sql postgresql left-join aggregate-functions 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    

所需的输出(只是 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

到目前为止的 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 获取并计算出现次数。但是如果 key 没有出现在 B 或 C 中,它就不会出现在输出中(例如输出中的 id=2)。我如何从表 A 开始我的选择并加入/联合 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);

您需要考虑某些 a_id 根本不存在于 a 和/或 b 中的可能性。 count() 永远不会返回 NULL,但面对 LEFT JOIN 时,这是一种冰冷的安慰,它让您得到 NULL 尽管如此,缺失行的值。您必须准备NULL。使用 COALESCE() .

或者 UNION ALL a_id 来自两个表,聚合,然后 JOIN:

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() 并且仍然不会丢失任何行。在这种情况下,您可能偶尔会得到 bc_ctNULL 值。

关于sql - 从多个表中获取外键的计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24745091/

相关文章:

mysql - 有效地只向用户显示他之前没有看到的项目(mysql)

python - 如何加速 SQLAlchemy 查询?

javascript - Sequelize 与 PostgreSQL 的关系 (generator-sql-fullstack)

mysql - 提取缺失数据的结果

mysql - 如何将 NOT IN 转换为 LEFT JOIN(或 NOT EXISTS)

sql - Grails将SQL转换为Grails条件查询

php - 如何将数组从经典asp发送到php页面中的表?

sql - 为什么在本地服务器上使用 OPENQUERY 不好?

python - 多个 Postgres 模式的 Django 单元测试失败

php - 如何通过连接另一个表来更新MySQL表列