简体   繁体   中英

MySQL outer join: why does selecting records in ON gives different results than selecting in WHERE?

Why do these two queries give different results?

This query gives all records regardless of the value of the deleted column. It's as if that selection is ignored:

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

This query only selects records where the deleted column is false, which is what I want.

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'

Why do the two queries give different results? I'm using MySQL version 5.5.37.

The logic for a left outer join is to take all the records from the first table. If there is one or more matches in the second table, then include those matches in the result set. If there are no matches, then still include the original record in the result set, with all the other columns being NULL. A match means that the on clause evaluates to true.

This applies to filtering on the first table. So in this expression:

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'

You think that you are filtering on mc.deleted = 'false' . However, this just means that there is no match (because the on clause evaluates to false). The record is still kept, because that is the logic of the left outer join .

When you move the condition on mc to the where clause, the filtering happens as you expect it to.

Because when an OUTER JOIN is being performed the filtering occurs at different times during query processing

WHERE clauses are performed on the result of the OUTER JOIN.

ON clauses are performed on the input to the OUTER JOIN.

This is also true for an INNER JOIN; but in that case the different processing times still identical results.

It's as if that selection is ignored:

Because you are using an outer join.

A left outer join means return all rows from the first table and if there are rows in the second table that match the join criteria, then line them up in the same row. Then apply the WHERE clause. If they don't match, you still get a row, just with NULL values for the second table.

Put another way, an outer join never dis-qualifies rows from being returned. A WHERE clause will, of course, as will an inner join .

You might ask, what effect do join conditions have for outer joins then if they don't disqualify rows? Simple, they specify, for a given row on the right, if it should line up with a row on the left.

So you think the filter is not being applied. It is applied, in fact, to choosing rows from the second table to go with the first.

with a left join, all records from the table mailing_category will be returned (then filtered by the WHERE query), regardless of whether the join found any rows in mailing_category_membership and if the join was not successful, every column in mailing_category_membership will be NULL. So, in the first query, your WHERE will also return every row from mailing_category where no match was found for the join.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM