MySQL外连接:为什么在ON中选择记录会产生与在WHERE中选择不同的结果?

时间:2014-07-19 03:19:50

标签: mysql

为什么这两个查询会产生不同的结果?

此查询提供所有记录,而不管已删除列的值如何。它好像忽略了这个选择:

SELECT mcm.record_id, mc.category, mc.category_id, mc.deleted, mcm.member_id
FROM mailing_category mc
    LEFT OUTER JOIN mailing_category_membership mcm
    ON mc.category_id = mcm.category_id
        AND mcm.member_id = 6346
        AND mc.deleted = 'false'
WHERE mcm.record_id IS NULL

此查询仅选择已删除列为false的记录,这就是我想要的。

SELECT mcm.record_id, mc.category, mc.category_id, mc.deleted, mcm.member_id
FROM mailing_category mc
    LEFT OUTER JOIN mailing_category_membership mcm
    ON mc.category_id = mcm.category_id
        AND mcm.member_id = 6346
WHERE mcm.record_id IS NULL
        AND mc.deleted = 'false'

为什么这两个查询会给出不同的结果?我使用的是MySQL 5.5.37版。

4 个答案:

答案 0 :(得分:2)

left outer join的逻辑是从第一个表中获取所有记录。如果第二个表中有一个或多个匹配项,则在结果集中包含这些匹配项。如果没有匹配项,则仍然在结果集中包含原始记录,其他所有列都为NULL。匹配意味着on子句的计算结果为true。

这适用于第一个表上的过滤。所以在这个表达式中:

FROM mailing_category mc LEFT OUTER JOIN
     mailing_category_membership mcm
     ON mc.category_id = mcm.category_id AND mcm.member_id = 6346 AND
        mc.deleted = 'false'

认为您正在mc.deleted = 'false'上过滤。但是,这只是意味着没有匹配(因为on子句的计算结果为false)。记录仍然保留,因为这是left outer join的逻辑。

当您将mc上的条件移动到where子句时,过滤会按预期进行。

答案 1 :(得分:1)

因为在执行OUTER JOIN时,在查询处理期间的不同时间进行过滤

对OUTER JOIN的结果执行WHERE子句。

对OUTER JOIN的输入执行ON子句。

INNER JOIN也是如此;但在这种情况下,不同的处理时间仍然是相同的结果。

答案 2 :(得分:1)

  
    

就好像忽略了这个选择:

  

因为您正在使用外部联接。

左外连接意味着返回第一个表中的所有行,如果第二个表中的行与连接条件匹配,则将它们排成同一行。然后应用WHERE子句。如果它们不匹配,您仍会得到一行,只有第二个表的NULL值。

换句话说,outer join永远不会取消返回行的资格。当然,WHERE条款与inner join一样。

您可能会问,如果连接条件没有取消对行的限制,那么连接条件对外连接有什么影响?很简单,它们为右边的给定行指定它是否应该与左边的行对齐。

所以你认为过滤器没有被应用。事实上,它应用于从第二个表中选择行以与第一个行一起使用。

答案 3 :(得分:0)

使用左连接,将返回表mailing_category中的所有记录(然后由WHERE查询过滤),无论连接是否在mailing_category_membership中找到任何行,如果连接不成功,mailing_category_membership中的每一列都将为NULL。因此,在第一个查询中,您的WHERE也将返回mailing_category中未找到匹配匹配项的每一行。