【问题标题】:MySQL JOIN independent of WHERE clauseMySQL JOIN 独立于 WHERE 子句
【发布时间】:2016-05-01 18:02:35
【问题描述】:

我有两张桌子:

debates
----------------------
id | name
----------------------
 1 | why is that?
 2 | why is the other?

opinions
---------------------
id | debate | opinion
---------------------
 1 | 1      | because
 2 | 1      | NULL

如果我使用 left join ON opinion.debate =debates.id 我可以得到两个辩论 (1, 2)。

如果我在 left join 上使用 where 子句 WHERE (opinions.opinion != '' AND opinion.opinion IS NOT NULL) 我只得到 id = 1 的辩论

如何获得两条记录但仍然保留条件,因为我使用它来计算记录?

例如。查询:

SELECT 

debates.id,
COUNT(opinions.id) AS total_opinions

FROM debates

LEFT JOIN 
`opinions` ON `opinions`.`debate` = `debates`.`id` 

WHERE 
`opinions`.`opinion` IS NOT NULL AND `opinions`.`opinion` != '' 

GROUP BY 
`debates`.`id`

应该返回:

debates
-------------------
id | total_opinions
-------------------
 1 | 1
 2 | 0

【问题讨论】:

  • 那么你怎么能得到辩论 2 你坚持认为 opinions.opinion IS NOT NULL ?首先左连接的要点是允许意见.意见为空,以便出现辩论 2。

标签: mysql join left-join where ambiguity


【解决方案1】:

WHERE 子句的谓词移动到ON

SELECT debates.id,
       COUNT(opinions.id) AS total_opinions    
FROM debates    
LEFT JOIN `opinions` 
ON `opinions`.`debate` = `debates`.`id`  AND
   `opinions`.`opinion` IS NOT NULL AND 
   `opinions`.`opinion` != ''     
GROUP BY `debates`.`id`

此查询将获取debates所有 记录,并与满足ON 谓词指定条件的opinions 记录相连接。如果没有匹配到NULL,则返回COUNT聚合函数。

Demo here

【讨论】:

  • 我不知道ON语句可以获得额外的条件而不是连接关系。谢谢。
【解决方案2】:

LEFT OUTER JOIN 的目的是允许列出一个表的所有行,即使这些行没有在另一个表中引用,并且如果存在这些条件,您会从另一个表中获得 NULL 值。因此,即使对其中一些没有意见,要获得所有辩论,您也可以这样做:

FROM debates
LEFT OUTER JOIN `opinions` ON `opinions`.`debate` = `debates`.`id` 

当辩论没有意见时,意见表中数据的所有列位置将为 NULL

如果您要计算意见的数量,那么请务必注意,COUNT() 函数仅在值为 NON NULL 时增加 1。因此,以下将自动计算正确的意见数量,而无需过滤掉 NULL。

SELECT 
      debates.id
    , COUNT(opinions.id) AS total_opinions
FROM debates
LEFT OUTER JOIN `opinions` ON `opinions`.`debate` = `debates`.`id` 
GROUP BY
      debates.id

现在,如果您确实在意见表中有意见是空白字符串的行,您可以这样做:

SELECT 
      debates.id
    , COUNT(opinions.id) AS total_opinions
FROM debates
LEFT OUTER JOIN `opinions` ON `opinions`.`debate` = `debates`.`id` 
                          AND `opinions`.`opinion` <> '' 
GROUP BY
      debates.id

或:

SELECT 
      debates.id
    , COUNT(case when `opinions`.`opinion` <> '' then opinions.id end) AS total_opinions
FROM debates
LEFT OUTER JOIN `opinions` ON `opinions`.`debate` = `debates`.`id` 
GROUP BY
      debates.id

【讨论】:

  • 感谢您的回答。 @Giorgos Betsos 解决方案完全相同。
  • 不一样。不需要将所有谓词移动到联接。例如,如果您正在计数,则根本不需要过滤 NULL。
  • 你说得对。 IS NOT NULL 条件不是必需的,实际上是多余的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-16
  • 1970-01-01
  • 2011-07-06
  • 2021-02-15
  • 1970-01-01
  • 1970-01-01
  • 2021-09-29
相关资源
最近更新 更多