在PostgreSQL中连接三个表后计算行数

时间:2015-08-27 22:39:27

标签: sql postgresql join left-join

假设我在PostgreSQL中有三个表:

table1 - id1, a_id, updated_by_id
table2 - id2, a_id, updated_by_id
Users  - id, display_name

假设我使用以下查询:

select count(t1.id1) from table1 t1 
left join table2 t2 on (t1.a_id=t2.a_id) 
full outer join users u1 t1.updated_by_id=u1.id)
full outer join users u2 t2.updated_by_id=u2.id) 
where u1.id=100;

我将50作为计数。

然而:

select count(t1.id1) from table1 t1 
left join table2 t2 on (t1.a_id=t2.a_id) 
full outer join users u1 t1.updated_by_id=u1.id)
full outer join users u2 t2.updated_by_id=u2.id) 
where u2.id=100;

我只获得25作为计数。

第二个查询中我的错误是什么?我能做些什么来获得相同的数量?

我的要求是有一个用户表,由多个表引用。我想获取完整的用户列表,并从不同的表中获取ID的数量。

但我单独参加的桌子会返回正确的计数,但其余的人不会返回正确的计数。任何人都可以建议一种方法来修改我的第二个查询以获得正确的计数吗?

1 个答案:

答案 0 :(得分:2)

要简化逻辑,请先聚合,稍后再加入。

猜测错过的详细信息,此查询会为您提供准确的计数,table1table2分别为所有用户分别引用每个用户的次数

SELECT *
FROM   users u
LEFT   JOIN (
   SELECT updated_by_id AS id, count(*) AS t1_ct
   FROM   table1
   GROUP  BY 1
   ) t1 USING (id)
LEFT   JOIN (
   SELECT updated_by_id AS id, count(*) AS t2_ct
   FROM   table2
   GROUP  BY 1
   ) t2 USING (id);

特别是,当连接在一起时,避免多个1-n关系相互重叠:

要仅检索单个或少数用户LATERAL加入速度会更快(Postgres 9.3 +):

SELECT *
FROM   users u
LEFT   JOIN  LATERAL (
   SELECT count(*) AS t1_ct
   FROM   table1
   WHERE  updated_by_id = u.id
   ) ON true
LEFT   JOIN  LATERAL (
   SELECT count(*) AS t2_ct
   FROM   table2
   WHERE  updated_by_id = u.id
   ) ON true
WHERE  u.id = 100;

解释感知差异

您报告的特定不匹配是由于FULL OUTER JOIN

的细节
  

首先,执行内连接。然后,对于T1中的每一行   不满足T2中任何行的连接条件,连接的行是   在T2列中添加了空值。另外,对于T2的每一行   不满足T1中任何行(连接行)的连接条件   添加了T1列中的空值。

因此,对于缺少的匹配,您将在相应的另一侧附加NULL值。 count()不计算NULL值。因此,您可以根据是否对u1.id=100u2.id=100进行过滤来获得不同的结果。

这只是为了解释,你这里不需要FULL JOIN。请改用现有的替代方案。