2010-07-15 11 views
13
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.foobar = 'somethingelse' 

Tener la cláusula y después de la cláusula where parece girar a la izquierda unirse en una combinación interna. El comportamiento que estoy viendo es que si no hay "algo malo" en la tabla Tres, se devolverán 0 filas.izquierda se unen se convierte en unión interna

Si muevo c.foobar = 'somethingelse' en la cláusula de unión, la unión almacenada actuará como una combinación de la izquierda.

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 
    AND c.foobar = 'somethingelse' 
    WHERE a.foo = 'something' 

¿Puede alguien indicarme alguna documentación que describa por qué sucede esto? Te lo agradezco mucho

Respuesta

31

Es por tu cláusula WHERE.

Cuando se especifica un valor en el lado derecho de la izquierda se unen en un WHERE cláusula (que es NOT NULL), se elimina necesariamente todas las NULL valores y se convierte esencialmente un INNER JOIN.

Si escribe, AND c.foobar = 'somethingelse' OR c.foobar IS NULL que resolverá el problema.

También puede mover la parte c.foobar a su predicado de unión, y eso también resolverá el problema.

+0

+1. buena explicación. –

+0

@DaveMarkle es el mismo caso cuando especifico el valor del lado derecho de una combinación izquierda en el grupo por o teniendo. (me refiero a que se convertirá de izquierda a interna) –

+0

@Dave Markle ¿Sabes qué sería más rápido, la cláusula WHERE o el predicado JOIN en un caso como este? – PerPlexSystem

3

La razón por la que está viendo esto es porque la combinación izquierda establece todas las columnas de c en NULL para aquellas filas que no existen en c (es decir, que no se pueden unir). Esto implica que la comparación c.foobar = 'somethingelse' no es verdadera, razón por la cual esas filas no se devuelven.

En el caso en que se mueve el c.foobar = 'somethingelse' en la condición de unión, que se unen aún está regresando esas filas (aunque con valores NULL) cuando la condición no es cierta.

0

Las uniones están haciendo su trabajo, entonces el where está eliminando los registros donde c.foobar <> 'somethingelse'.

El efecto parece una unión interna pero en realidad no lo es.

0

A Left Unir devuelve todo de la tabla de la izquierda (tabla Dos en su ejemplo) y las filas correspondientes de la tabla de la derecha (tabla Tres en su ejemplo). Cuando filtras algo en el lado derecho de la combinación izquierda (es decir, tabla Tres) y no cuentas por valores que no coinciden, efectivamente estás requiriendo que exista un valor y que el valor sea 'algo' que es el equivalente de un valor interno unirse. Si lo que estamos tratando de hacer es encontrar todas las filas tableTwo que no tienen una fila en tableThree con un valor foobar de 'algo', puede mover el filtrado en la cláusula on:

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 

La adición final , c.pk Is Null filtros para valores que no tienen un valor TableThree con un valor foobar de 'something'. Si solo quieres ver los valores tableThree cuando tienen un valor foobar de 'something' (y null de lo contrario), entonces quita el filtro adicional I agregado de c.pk Is Null.

0

primera de casos (donde el c.foobar es en la cláusula where) el filtrado por el c.foobar sucede después de las combinaciones que se han producido (de que ocurran correctamente), de modo que filtre-cabo de manera eficaz todos los registros resultantes que hacen no tiene un 'somethingelse' allí ..

segundo caso el c.foobar es parte de la unión, por lo que evalúa a unirse a tiempo y sólo controla la salida de la unión, y no el conjunto de registros final (vuelve null donde la unión falla) ..

0

la izquierda JOIN produce NULLs donde no hay filas coincidentes. En este caso, c.foobar será NULL para las filas que no coincidan. Pero su cláusula WHERE está buscando un valor específico: 'somethingelse', y por lo tanto filtrará todos los valores NULL. Como INNER JOIN tampoco produce valores NULL en el lado derecho, los dos tienen el mismo aspecto. Puede agregar 'O c.foobar IS NULL' para volver a permitir los valores nulos.

Cuando mueve la condición a la cláusula ON, se convierte en parte de la coincidencia de fila JOIN, en lugar del filtro final. La combinación de unión puede fallar y la combinación externa devuelve NULL en los casos donde 'c.foobar' es NULL o no 'somethingelse'.

Ver

1

La cláusula where se realiza después de la unión. Esto no tiene importancia para las uniones internas, pero sí para las combinaciones externas.

Shorten Ejemplo

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

No resulta un LEFT JOIN en un INNER JOIN, pensaba que el efecto puede aparecer ser el mismo. Cuando se establece la condición WHERE

Y c.foobar = 'somethingelse'

que estés deshacerse de todos los casos que permiten un LEFT JOIN para actuar como lo hace. En este caso, algunos de los valores para c.foobar serán NULL. Establecer esto en la condición JOIN todavía permite resultados de JOINT LEFT JOIN que no coinciden, restringiendo solo lo que se devuelve para los resultados de C.