Quiero hacer una unión externa completa en MySQL. es posible? ¿MySQL admite una unión externa completa?
sql
mysql
join
outer-join
full-outer-join
Spencer
fuente
fuente
Respuestas:
No tiene FULL JOINS en MySQL, pero puede emularlos .
Para un código SAMPLE transcrito de esta pregunta SO , tiene:
con dos tablas t1, t2:
La consulta anterior funciona para casos especiales en los que una operación FULL OUTER JOIN no produciría filas duplicadas. La consulta anterior depende del
UNION
operador de conjunto para eliminar las filas duplicadas introducidas por el patrón de consulta. Podemos evitar la introducción de filas duplicadas mediante el uso de un patrón anti-unión para la segunda consulta, y luego usar un operador de conjunto UNION ALL para combinar los dos conjuntos. En el caso más general, donde una UNIÓN COMPLETA EXTERNA devolvería filas duplicadas, podemos hacer esto:fuente
(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
t1
yt2
, la consulta en esta respuesta devuelve un conjunto de resultados que emula FULL OUTER JOIN. Pero en el caso más general, por ejemplo, la lista SELECT no contiene suficientes columnas / expresiones para hacer que las filas devueltas sean únicas, entonces este patrón de consulta es insuficiente para reproducir el conjunto que produciría aFULL OUTER JOIN
. Para obtener una emulación más fiel, necesitaríamos unUNION ALL
operador establecido, y una de las consultas necesitaría un patrón anti-unión . El comentario de Pavle Lekic (arriba) da el patrón de consulta correcto .La respuesta que dio Pablo Santa Cruz es correcta; sin embargo, en caso de que alguien se tope con esta página y quiera más aclaraciones, aquí hay un desglose detallado.
Tablas de ejemplo
Supongamos que tenemos las siguientes tablas:
Uniones internas
Una unión interna, como esta:
Solo obtendríamos registros que aparecen en ambas tablas, así:
Las uniones internas no tienen una dirección (como izquierda o derecha) porque son explícitamente bidireccionales; necesitamos una coincidencia en ambos lados.
Uniones externas
Las uniones externas, por otro lado, son para encontrar registros que pueden no tener una coincidencia en la otra tabla. Como tal, debe especificar qué lado de la unión puede tener un registro faltante.
LEFT JOIN
yRIGHT JOIN
son taquigrafía paraLEFT OUTER JOIN
yRIGHT OUTER JOIN
; Usaré sus nombres completos a continuación para reforzar el concepto de combinaciones externas frente a combinaciones internas.Izquierda combinación externa
Una unión externa izquierda, como esta:
... nos obtendría todos los registros de la tabla de la izquierda, independientemente de si tienen una coincidencia en la tabla de la derecha, de esta manera:
Unión externa derecha
Una unión externa derecha, como esta:
... nos obtendría todos los registros de la tabla derecha, independientemente de si tienen una coincidencia en la tabla izquierda, como este:
Unión externa completa
Una combinación externa completa nos daría todos los registros de ambas tablas, independientemente de si tienen una coincidencia en la otra tabla, con NULL en ambos lados donde no hay coincidencia. El resultado se vería así:
Sin embargo, como señaló Pablo Santa Cruz, MySQL no es compatible con esto. Podemos emularlo haciendo una UNIÓN de una unión izquierda y una unión derecha, así:
Puede pensar en a
UNION
como que significa "ejecutar ambas consultas, luego apilar los resultados uno encima del otro"; algunas de las filas provendrán de la primera consulta y algunas de la segunda.Cabe señalar que un
UNION
en MySQL eliminará los duplicados exactos: Tim aparecería en ambas consultas aquí, pero el resultado de lasUNION
únicas lo enumera una vez. El colega de mi gurú de bases de datos cree que no se debe confiar en este comportamiento. Entonces, para ser más explícitos al respecto, podríamos agregar unaWHERE
cláusula a la segunda consulta:Por otro lado, si quería ver duplicados por alguna razón, usted podría utilizar
UNION ALL
.fuente
FULL OUTER JOIN
. No hay nada de malo en hacer consultas de esa manera y usar UNION para eliminar esos duplicados. Pero para replicar realmente aFULL OUTER JOIN
, necesitamos una de las consultas para ser un anti-join.UNION
operación eliminará esos duplicados; pero también elimina TODAS las filas duplicadas, incluidas las filas duplicadas que serían devueltas por una UNIÓN COMPLETA EXTERNA. Para emulara FULL JOIN b
, el patrón correcto es(a LEFT JOIN b) UNION ALL (b ANTI JOIN a)
.El uso de una
union
consulta eliminará duplicados, y esto es diferente al comportamiento defull outer join
que nunca elimina ningún duplicado:Este es el resultado esperado de
full outer join
:Este es el resultado de usar
left
yright Join
conunion
:[SQL Fiddle]
Mi consulta sugerida es:
Resultado de la consulta anterior que es igual al resultado esperado:
[SQL Fiddle]
Decidí agregar otra solución que proviene de la
full outer join
visualización y las matemáticas, no es mejor que la anterior pero es más legible:[SQL Fiddle]
fuente
FULL OUTER JOIN
. Esta publicación de blog también lo explica bien: para citar el Método 2: "Esto maneja las filas duplicadas correctamente y no incluye nada que no debería. Es necesario usar UNION ALL en lugar de UNION simple, lo que eliminaría los duplicados que quiero mantener. Esto puede ser significativamente más eficiente en grandes conjuntos de resultados, ya que no hay necesidad de ordenar y eliminar duplicados ".MySql no tiene la sintaxis FULL-OUTER-JOIN. Tienes que emular haciendo LEFT JOIN y RIGHT JOIN de la siguiente manera:
Pero MySql tampoco tiene una sintaxis RIGHT JOIN. De acuerdo con la simplificación de combinación externa de MySql , la combinación derecha se convierte en la combinación izquierda equivalente cambiando t1 y t2 en la cláusula
FROM
yON
en la consulta. Por lo tanto, MySql Query Optimizer traduce la consulta original en lo siguiente:Ahora, no hay ningún daño en escribir la consulta original tal como está, pero si tiene predicados como la cláusula WHERE, que es un predicado anterior a la unión o un predicado AND en la
ON
cláusula, que es un predicado durante la unión , entonces usted podría querer echar un vistazo al diablo; que está en detallesMySql query optimizer verifica rutinariamente los predicados si son rechazados por nulo . Ahora, si ha realizado la UNIÓN DERECHA, pero con el predicado WHERE en la columna de t1, entonces podría correr el riesgo de encontrarse con un escenario de rechazo nulo .
Por ejemplo, la siguiente consulta:
se traduce a lo siguiente por el Optimizador de consultas
Por lo tanto, el orden de las tablas ha cambiado, pero el predicado todavía se aplica a t1, pero t1 ahora está en la cláusula 'ON'. Si t1.col1 se define como
NOT NULL
columna, entonces esta consulta será rechazada por nulo .MySql convierte cualquier unión externa (izquierda, derecha, completa) que sea rechazada por nulo en una unión interna.
Por lo tanto, los resultados que podría esperar podrían ser completamente diferentes de lo que está devolviendo MySql. Puede pensar que es un error con RIGHT JOIN de MySql, pero eso no está bien. Así es como funciona el optimizador de consultas MySql. Por lo tanto, el desarrollador a cargo debe prestar atención a estos matices cuando está construyendo la consulta.
fuente
En SQLite deberías hacer esto:
fuente
Ninguna de las respuestas anteriores es realmente correcta, porque no siguen la semántica cuando hay valores duplicados.
Para una consulta como (de este duplicado ):
El equivalente correcto es:
Si necesita que esto funcione con
NULL
valores (que también pueden ser necesarios), utilice elNULL
operador de comparación seguro, en<=>
lugar de=
.fuente
FULL OUTER JOIN
cuando laname
columna es nula. Launion all
consulta con patrón anti-unión debería reproducir correctamente el comportamiento de la unión externa, pero la solución más apropiada depende del contexto y de las restricciones que están activas en las tablas.union all
, pero esa respuesta pierde un patrón anti-unión en la primera o la segunda consulta que mantendrá duplicados existentes pero evita agregar nuevos. Dependiendo del contexto, otras soluciones (como esta) podrían ser más apropiadas.Se modificó la consulta de shA.t para obtener más claridad:
fuente
Puedes hacer lo siguiente:
fuente
¿Qué dijiste sobre la solución Cross join ?
fuente
select (select count(*) from t1) * (select count(*) from t2))
filas en el conjunto de resultados.fuente
También es posible, pero debe mencionar los mismos nombres de campo en select.
fuente
Arreglo la respuesta, y las obras incluyen todas las filas (según la respuesta de Pavle Lekic)
fuente
tablea
que no coincidentableb
y viceversa. Intenta hacerloUNION ALL
, lo que solo funcionaría si estas dos tablas tienen columnas ordenadas de manera equivalente, lo que no está garantizado.Responder:
Se puede recrear de la siguiente manera:
El uso de una respuesta UNION o UNION ALL no cubre el caso límite donde las tablas base tienen entradas duplicadas.
Explicación:
Hay un caso extremo que UNION o UNION ALL no pueden cubrir. No podemos probar esto en mysql ya que no admite FULL OUTER JOINs, pero podemos ilustrar esto en una base de datos que sí lo admite:
La solución UNION:
Da una respuesta incorrecta:
La solución UNION ALL:
También es incorrecto.
Mientras que esta consulta:
Da lo siguiente:
El orden es diferente, pero por lo demás coincide con la respuesta correcta.
fuente
UNION ALL
solución. Además, presenta una soluciónUNION
que sería más lenta en tablas de origen grandes debido a la desduplicación requerida. Finalmente, no se compilaría, porque el campoid
no existe en la subconsultatmp
.UNION ALL
solución: ... también es incorrecta". El código que presente deja de lado la exclusión de intersección de la unión derecha (where t1.id1 is null
) que debe proporcionarse enUNION ALL
. Es decir, su solución supera a todas las demás, solo cuando una de esas otras soluciones se implementa incorrectamente. Sobre "ternura", punto tomado. Eso fue gratuito, mis disculpas.El estándar SQL dice
full join on
que lasinner join on
filas de launion all
tabla izquierda no coinciden filas extendidas por nulosunion all
filas de tabla derecha extendidas por nulos. Es decir,inner join on
filasunion all
filasleft join on
pero noinner join on
union all
filasright join on
pero noinner join on
.Es decir,
left join on
filasunion all
right join on
filas no adentroinner join on
. O si sabe que suinner join on
resultado no puede tener un valor nulo en una columna de tabla derecha en particular, entonces las "right join on
filas no incluidasinner join on
" son filasright join on
con laon
condición extendida porand
esa columnais null
.Es decir, filas igualmente
right join on
union all
apropiadasleft join on
.De Cuál es la diferencia entre “INNER JOIN” y “OUTER JOIN”? :
fuente