2010-05-21 7 views
7

obtengo resultados diferentes basados ​​en una condición de filtro en una consulta en función de dónde coloco la condición del filtro. ¿Mi pregunta esSQL estándar con respecto a las condiciones de unión externa izquierda y dónde

  • ¿Hay alguna diferencia técnica? entre estas consultas?
  • ¿Hay algo en el estándar SQL que explica las diferentes de registros de las consultas?

Dado el escenario simplificado:

--Table: Parent Columns: ID, Name, Description 
--Table: Child Columns: ID, ParentID, Name, Description 

--Query 1 
SELECT p.ID, p.Name, p.Description, c.ID, c.Name, c.Description 
FROM Parent p 
    LEFT OUTER JOIN Child c ON (p.ID = c.ParentID) 
WHERE c.ID IS NULL OR c.Description = 'FilterCondition' 

--Query 2 
SELECT p.ID, p.Name, p.Description, c.ID, c.Name, c.Description 
FROM Parent p 
    LEFT OUTER JOIN Child c 
    ON (p.ID = c.ParentID AND c.Description = 'FilterCondition') 

que asumió las consultas volverían los mismos conjuntos de resultados y me sorprendió cuando no lo hicieron. Estoy usando MS SQL2005 y en las consultas reales, la consulta 1 arrojó ~ 700 filas y la consulta 2 devolvió ~ 1100 filas y no pude detectar un patrón en el que se devolvieron las filas y qué filas se excluyeron. Todavía había muchas filas en la consulta 1 con filas secundarias con datos y datos NULL. Prefiero el estilo de la consulta 2 (y creo que es más óptimo), pero pensé que las consultas arrojarían los mismos resultados.

Editar/resumen:

Hubo algunas grandes respuestas proporcionadas aquí. Me costó mucho elegir a quién otorgar la respuesta. Decidí ir con mdma ya que era la primera respuesta y una de las más claras. Sobre la base de las respuestas suministradas, aquí está mi resumen:

resultados posibles:

  • A: Padres que no tienen hijos
  • B: Los padres con niños
  • | -> B1: Padres niños donde no coincide con el niño el filtro
  • \ -> B2: padres con hijos donde 1 o más coinciden con el filtro

resultados de la consulta:

  • de consulta 1 vuelve (A, B2)
  • Consulta 2 devuelve (A, B1, B2)

de consulta 2 siempre devuelve un padre debido la izquierda se une En la consulta 1, la cláusula WHERE se realiza después de la combinación left, por lo que se excluyen los padres con hijos donde ninguno de los hijos coincide con el filtro (caso B1).

Nota: sólo la información de los padres se devuelve en caso B1, B2 y en caso únicamente se devuelve la información de padre/hijo que coincida con el filtro.

HLGEM proporciona un buen enlace:

http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

Respuesta

9

La primera consulta devolverá los casos en que el padre no tiene hijos, o cuando algunos de los niños que coincida con la condición de filtro.Específicamente, se omitirán los casos en que el padre tiene un hijo, pero no coincide con la condición del filtro.

La segunda consulta devolverá una fila para todos los padres. Si no hay coincidencia en la condición del filtro, se devolverá un NULL para todas las columnas de c. Esta es la razón por la que obtiene más filas en la consulta 2: los padres con hijos que no coinciden con la condición de filtro se envían con valores secundarios NULL, donde en la primera consulta se filtran.

10

Sí, hay una gran diferencia. Cuando coloca filtros en la cláusula ON en una unión IZQUIERDA, el filtro se aplica antes de los resultados se unen a la tabla externa. Cuando aplica un filtro en la cláusula WHERE, sucede después de que se haya aplicado LEFT JOIN.

En resumen, la primera consulta excluirá las filas donde hay filas secundarias pero la descripción secundaria no es igual a la condición del filtro, mientras que la segunda consulta siempre devolverá una fila para el elemento primario.

+0

Gracias. Entiendo la diferencia en términos de rendimiento, pero tengo más curiosidad sobre los diferentes resultados. – Ryan

+0

@Ryan - No se trata de rendimiento. El lugar donde se aplica el filtrado puede marcar la diferencia en términos del conjunto de resultados adecuado. – Thomas

+0

Entendido. Gracias. – Ryan

0

Veo un par de diferencias que pueden hacer que los resultados varíen.En la primera consulta, tiene LEFT OUTER JOIN Child c ON (p.ID = c.ParentID) y luego en la segunda consulta tiene LEFT OUTER JOIN Child c ON (p.ID = c.ParentID AND c.Description = 'FilterCondition') y esto hace que la segunda consulta devuelva a todos los padres con hijos que cumplan su condición La primera condición también devolverá a los padres sin hijos. También observe la precedencia de las condiciones de unión y dónde están las condiciones.

1

los padres que solo tienen hijos con description != 'FilterCondition' no aparecerán en la consulta 1 porque la cláusula WHERE se evalúa después de que se unen las filas.

1

La primera consulta devuelve menos filas porque solo devuelve filas que no tienen hijos o tienen elementos secundarios que coinciden con las condiciones del filtro.

La cláusula WHERE excluye el resto (los que sí tienen hijos, pero no coinciden con la condición de filtro.)

La consulta segunda muestra las tres condiciones anteriores.

2

Para este conjunto de registros:

parent 

id 
1 

child 

id parent filter 
1  1  OtherCondition 
2  1  OtherCondition 

, la primera consulta devolvería 0 registros, mientras que el segundo volvería 1 registro:

WITH parent (id) AS 
     (
     SELECT 1 
     ), 
     child (id, parent, condition) AS 
     (
     SELECT 1, 1, 'OtherCondition' 
     UNION ALL 
     SELECT 2, 1, 'OtherCondition' 
     ) 
SELECT * 
FROM parent 
LEFT JOIN 
     child 
ON  child.parent = parent.id 

/* The children are found, so no fake NULL records returned */ 

1 1 1 OtherCondition 
1 2 1 OtherCondition 

Ahora añadiendo WHERE cláusula:

WITH parent (id) AS 
     (
     SELECT 1 
     ), 
     child (id, parent, condition) AS 
     (
     SELECT 1, 1, 'OtherCondition' 
     UNION ALL 
     SELECT 2, 1, 'OtherCondition' 
     ) 
SELECT * 
FROM parent 
LEFT JOIN 
     child 
ON  child.parent = parent.id  
WHERE child.id IS NULL OR child.condition = 'FilterCondition' 

WHERE cláusula filtra los registros devueltos en el paso anterior y ningún registro coincide con la condición.

Mientras éste:

WITH parent (id) AS 
     (
     SELECT 1 
     ), 
     child (id, parent, condition) AS 
     (
     SELECT 1, 1, 'OtherCondition' 
     UNION ALL 
     SELECT 2, 1, 'OtherCondition' 
     ) 
SELECT * 
FROM parent 
LEFT JOIN 
     child 
ON  child.parent = parent.id  
     AND child.condition = 'FilterCondition' 

1 NULL NULL NULL 

devuelve un registro falso.

+0

Gran ejemplo detallado. Muy agradable. No sé si lo llamaría un registro "falso", ya que es una combinación de la izquierda y es de esperar que las columnas de la tabla externa sean NULL a veces. Probablemente diría que la consulta 2 siempre devuelve un padre mientras que la consulta 1 devuelve padres que no tienen hijos o padres con hijos que coinciden explícitamente con la condición del filtro. Muchas gracias por el ejemplo. – Ryan

3

Poner la condición en la cláusula where convierte en una combinación interna (a menos que utilice algo donde donde id es nulo que le da no registra enla tabla) ver esto por una explicación más completa:

http://wiki.lessthandot.com/index.php/WHERE_conditions_on_a_LEFT_JOIN

+0

Me gusta el enlace. Bonito. – Ryan

+1

+1, aunque esto, por supuesto, depende de la condición. Digamos, colocar una condición como 'id IS NULL' convierte un' LEFT JOIN' en 'NOT EXISTS' (y la mayoría de los motores incluso lo optimizan correctamente). Cualquier igualdad o desigualdad, por supuesto, lo convertiría en una unión interna. – Quassnoi

Cuestiones relacionadas