postgresql 两个SQL LEFT JOIN产生错误的结果

41ik7eoe  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(4)|浏览(188)

我有三张table:

users(id, account_balance)
grocery(user_id, date, amount_paid)
fishmarket(user_id, date, amount_paid)

字符串
fishmarketgrocery两个表都可能在同一个user_id中多次出现,但日期和支付金额不同,或者对于任何给定的用户都没有任何内容。当我尝试以下查询时:

SELECT
     t1."id" AS "User ID",
     t1.account_balance AS "Account Balance",
     count(t2.user_id) AS "# of grocery visits",
     count(t3.user_id) AS "# of fishmarket visits"
FROM users t1
LEFT OUTER JOIN grocery t2 ON (t2.user_id=t1."id") 
LEFT OUTER JOIN fishmarket t3 ON (t3.user_id=t1."id") 
GROUP BY t1.account_balance,t1.id
ORDER BY t1.id


它会产生错误的结果:"1", "12", "12"
但是,当我尝试对一个表执行LEFT JOIN时,它会为groceryfishmarket访问产生正确的结果,即"1", "3", "4"
我做错什么了?
我用的是PostgreSQL 9.1。

insrf1ej

insrf1ej1#

从左到右处理联接(除非括号另有说明)。如果您LEFT JOIN(或仅JOIN,类似效果)一个用户购买三个杂货,您将获得3行(1 x 3)。如果您为同一用户加入4个fishmarkets,则会得到12个(3 x 4)行,* 乘以 * 结果中的前一个计数,而不是像你希望的那样,* 加上 *。
从而使杂货店和鱼市的访问量成倍增加。
你可以让它像这样工作:

SELECT u.id
     , u.account_balance
     , g.grocery_visits
     , f.fishmarket_visits
FROM   users u
LEFT   JOIN (
   SELECT user_id, count(*) AS grocery_visits
   FROM   grocery
   GROUP  BY user_id
   ) g ON g.user_id = u.id
LEFT   JOIN (
   SELECT user_id, count(*) AS fishmarket_visits
   FROM   fishmarket
   GROUP  BY user_id
   ) f ON f.user_id = u.id
ORDER  BY u.id;

字符串
为了获得一个或几个用户的聚合值,* 相关子查询 * like @Vince provided就可以了。对于整个表或它的主要部分,聚合n个表并连接到结果 * 一次 (更)有效。这样,我们也不需要在外部查询中使用另一个GROUP BY
grocery_visitsfishmarket_visits
*NULL,用于在各自的表中没有任何相关条目的用户。如果您需要0(或任何任意数字),请在外部SELECT中使用COALESCE**:

SELECT u.id
     , u.account_balance
     , COALESCE(g.grocery_visits   , 0) AS grocery_visits
     , COALESCE(f.fishmarket_visits, 0) AS fishmarket_visits
FROM   ...

drkbr07n

drkbr07n2#

对于您的原始查询,如果您去掉group by以查看预分组的结果,您将看到为什么要创建接收的计数。
也许下面的查询利用子查询将实现您的预期结果:

SELECT
 t1."id" AS "User ID",
 t1.account_balance AS "Account Balance",
 (SELECT count(*) FROM grocery     t2 ON (t2.user_id=t1."id")) AS "# of grocery visits",
 (SELECT count(*) FROM fishmarket  t3 ON (t3.user_id=t1."id")) AS "# of fishmarket visits"
FROM users t1
ORDER BY t1.id

字符串

dnph8jn4

dnph8jn43#

这是因为当用户表连接到杂货表时,有3条记录匹配。然后这3条记录中的每一条都与fishmarket中的4条记录匹配,产生12条记录。您需要子查询来获得您要查找的内容。

trnvg8h3

trnvg8h34#

SELECT
     t1."id" AS "User ID",
     t1.account_balance AS "Account Balance",
     Sum(Case When t2.user_id is null then 0 else 1 end) AS "# of grocery visits",
     Sum(Case When t3.user_id is null then 0 else 1 end) AS "# of fishmarket visits"
FROM users t1
LEFT OUTER JOIN grocery t2 ON (t2.user_id=t1."id") 
LEFT OUTER JOIN fishmarket t3 ON (t3.user_id=t1."id") 
GROUP BY t1.account_balance,t1.id
ORDER BY t1.id

字符串
上面还将允许您根据需要添加其他标准

相关问题