left join turns into inner join

后端 未结 8 757
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-29 06:24
SELECT
a.foo
b.bar
c.foobar
FROM tableOne AS a
INNER JOIN tableTwo AS b ON a.pk = b.fk
LEFT JOIN tableThree AS c ON b.pk = c.fk
WHERE a.foo = \'something\'
AND c.foo         


        
相关标签:
8条回答
  • 2020-11-29 06:56

    The 'where' clause is performed after the join. This doesn't matter for inner joins but matters for outer joins.

    Shorten Example

    SELECT b.bar,c.foobar FROM tableTwo AS b LEFT JOIN tableThree AS c ON b.pk=c.fk WHERE c.foobar='somethingelse'
    
    Raw data                  Outer Join Result        Select Result
    b.pk c.fk c.foorbar       b.pk c.fk c.foorbar      c.foorbar
    1    1    something       1    1    something      <not in result set>
    1    1    somethingelse   1    1    somethingelse  somethingelse
    
    
    SELECT b.bar,c.foobar FROM tableTwo AS b LEFT JOIN tableThree AS c ON b.pk=c.fk AND c.foobar='somethingelse'
    
    Raw data                  Outer Join Result        Select Result
    b.pk c.fk c.foorbar       b.pk c.fk c.foorbar      c.foorbar
    1    1    something       1    null null           null
    1    1    somethingelse   1    1    somethingelse  somethingelse
    
    0 讨论(0)
  • 2020-11-29 06:56

    The joins are doing their work, then the where is removing the records where c.foobar <> 'somethingelse'.

    The effect looks like an inner join but actually isn't.

    0 讨论(0)
  • 2020-11-29 06:59

    The LEFT JOIN produces NULLs where there are no matching rows. In this case, c.foobar will be NULL for the non-matching rows. But your WHERE clause is looking for a specific value: 'somethingelse', and so will filter out all the NULL values. Since an INNER JOIN also produces no NULL values on the right side, the two look the same. You can add ' OR c.foobar IS NULL' to allow the null values back in.

    When you move the condition to the ON clause, it becomes part of the JOIN row matching, rather than the final filter. The join match may fail, and the outer join then returns NULLs on cases where 'c.foobar' is NULL or not 'somethingelse'.

    See

    • IS NULL
    • SQL Joins
    0 讨论(0)
  • 2020-11-29 07:05

    A Left Join returns everything from the left table (tableTwo in your example) and any matching rows from the table on the right (tableThree in your example). When you filter on something on the right side of the left join (i.e. tableThree) and you do not account for non-matching values you are effectively requiring that a value exist and that the value be 'something' which is the equivalent of an inner join. If what you are trying to do is to find all tableTwo rows which do not have a row in tableThree with a foobar value of 'something', you can move the filtering into the on clause:

    Select a.foo, b.bar, c.foobar
    From tableOne As a
        Inner Join tableTwo as b
            On b.fk = a.pk
        Left Join tableThree as c
            On c.fk = b.pk
                And c.foobar = 'something'
    Where a.foo = 'something'
        And c.pk Is Null
    

    The final addition, c.pk Is Null filters for values that do not have a tableThree value with a foobar value of 'something'.If just want to see tableThree values when they have a foobar value of 'something' (and nulls otherwise), then remove the additional filter I added of c.pk Is Null.

    0 讨论(0)
  • 2020-11-29 07:11

    It doesn't turn a LEFT JOIN into an INNER JOIN, thought the effect may appear to be the same. When you set the WHERE condition

    AND c.foobar = 'somethingelse'

    you're getting rid of all the cases that allow a LEFT JOIN TO act as it does. In this case, some of the values for c.foobar will be NULL. Setting this on the JOIN condition still allows non-matching LEFT JOIN results, only restricting what is returned for C results.

    0 讨论(0)
  • 2020-11-29 07:17

    The reason you're seeing this is because the left join sets all columns of c to NULL for those rows that don't exist in c (i.e. that can't be joined). This implies that the comparison c.foobar = 'somethingelse' is not true, which is why those rows are not being returned.

    In the case where you move the c.foobar = 'somethingelse' into the join condition, that join is still returning those rows (albeit with NULL values) when the condition is not true.

    0 讨论(0)
提交回复
热议问题