2008-10-09 12 views
16

¿Por qué es importante el orden de las tablas cuando se combina una unión interna & interna? la siguiente falla con postgres:unión interna y unión externa; ¿Es importante el orden de las tablas?

SELECT grp.number AS number,  
     tags.value AS tag 
FROM groups grp, 
    insrel archiverel 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 AND  
     archiverel.dnumber = grp.number 

con resultado:

ERROR: invalid reference to FROM-clause entry for table "grp" LINE 5: LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.d... 
^ HINT: There is an entry for table "grp", but it cannot be referenced from this part of the query. 

cuando los grupos se invierten en los de ella todas las obras:

SELECT grp.number AS number,  
     tags.value AS tag 
FROM insrel archiverel, 
     groups grp 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 AND  
     archiverel.dnumber = grp.number 
+0

Eso es muy interesante. Tiene que tener algo que ver con mezclar convenciones de unión. ¡Estoy un poco sorprendido de que la segunda versión funcione! –

Respuesta

20

Creo que puedes pensar en esto como un problema de precedencia del operador.

Cuando se escribe esto:

FROM groups grp, 
    insrel archiverel 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 

Creo que es interpretado por el analizador de esta manera:

FROM groups grp, 
(
    (
    insrel archiverel 
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
) 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
) 

Si es así, entonces en el más interno unirse a "GRP" no está consolidado.

Cuando invierte las líneas con "grupos" y "insrel", la unión más interna se aplica a "grupos" y "ownrel", por lo que funciona.

Probablemente esto funcionaría así:

FROM groups grp 
     JOIN insrel archiverel ON archiverel.dnumber = grp.number 
    LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
    LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 
+0

Tienes razón, usar una unión más bien en Insrel de hecho funciona y parece más lógica también –

5

Debido a que en la primera GRP es no es parte de la unión a la que pertenece la cláusula ON.

+0

Este es el único comentario que tiene sentido para mí y solucionó mi consulta. Moví una tabla en mi cláusula FROM para ser el último en la cláusula FROM y solucionó el error. –

4

No sé qué está causando ese comportamiento, si es un error o por diseño, pero debería funcionar bien si se queda con una forma de unión o la otra.

SELECT grp.number AS number,  
     tags.value AS tag 
FROM groups grp 
JOIN insrel archiverel ON archiverel.dnumber = grp.number 
LEFT OUTER JOIN ownrel ownrel ON grp.number = ownrel.dnumber 
LEFT OUTER JOIN tags tags ON tags.number = ownrel.snumber 
WHERE archiverel.snumber = 11128188 

Me gustaría saber más si el comportamiento es por diseño.

2

Para una unión interna, el orden de las tablas no es importante.

Para una unión externa, lo es. Todas se incluirán las filas de la tabla en el lado especificado (¿es una combinación IZQUIERDA o DERECHA), mientras que solo las filas que coinciden con los criterios de unión se incluirán en la tabla del otro lado.

Dado que OUTER JOINS mantiene todas las filas de un lado, se dice que (en general) aumentan los conjuntos de resultados. INNER JOINS solo mantiene las filas de ambos lados si coinciden, por lo que se dice (en general) para reducir los conjuntos de resultados. Por lo tanto, normalmente desea hacer sus UNIONES INTERNAS antes de las UNIONES EXTERNAS (cuando sea posible).

En su caso, es casi seguro un resultado de la malvada sintaxis A, B.

+0

true pero no es el orden de las uniones que causa el problema sino el orden en la cláusula –

+0

@Thies: WTFalse. El orden de las uniones se especifica en la cláusula from, por lo que el "orden de las uniones" es realmente "el orden de las uniones en la cláusula from", y ese * es * el problema, porque el orden importa. Si realiza uniones externas antes de uniones internas, las uniones internas reducen el conjunto de resultados que intentó mantener con la unión externa; por lo tanto, debe hacer las uniones inclusivas (externas) después de las uniones internas (exclusivas); de lo contrario, las uniones externas son inútiles. – Triynko

18

No creo que nadie haya explicado esto o lo haya explicado muy bien. Está combinando combinaciones de 'estilo antiguo' (theta) y 'nuevo estilo' (ANSI), que sospecho fuertemente que se están agrupando de formas que no espera. Mírelo de esta manera:

SELECT * FROM a, b JOIN c ON a.x = c.x 

es como decir

SELECT * FROM a, (b JOIN c on a.x = c.x) 

donde lo corchetes representa un montón de mesas fusionado en una sola tabla virtual, a unir con una teta a unirse en contra 'un'. Obviamente, la tabla 'a' no puede ser parte de la unión ya que solo se unirá a ella más tarde. Invierta, y lo está haciendo

SELECT * FROM b, (a JOIN c on a.x = c.x) 

que es perfectamente comprensible y tan fino. No estoy seguro de por qué no estás usando la sintaxis de unión ANSI para todo, parece un poco raro (y cruel para la persona que tiene que mantenerlo)

+0

Eso tiene que ser lo que está pasando. Sospecho que la implementación no esperaba que las personas mezclaran la sintaxis, y aunque lo hicieran, no existe un estándar que defina el comportamiento de la sintaxis mixta. –

+0

sí, mezclarlos es un viejo hábito que de hecho complica la lógica. –

Cuestiones relacionadas