¿Cómo hacer una UNIÓN COMPLETA EXTERNA en MySQL?

654

Quiero hacer una unión externa completa en MySQL. es posible? ¿MySQL admite una unión externa completa?

Spencer
fuente
2
posible duplicado del error de sintaxis de unión externa completa
Joe Stefanelli el
44
Esta pregunta tiene mejores respuestas
Julio Marins
Cuidado con las respuestas aquí. El estándar SQL dice que la unión completa en es unión interna en filas, une todas las filas de la tabla izquierda sin igualar extendidas por nulos, unen todas las filas de la tabla derecha extendidas por nulos. La mayoría de las respuestas aquí son incorrectas (vea los comentarios) y las que no están equivocadas no manejan el caso general. A pesar de que hay muchos votos a favor (injustificados). (Ver mi respuesta.)
philipxy
¿Qué pasa cuando intentas unirte mediante claves no primarias / columnas agrupadas? como si tuviera una consulta de ventas por estado "estado", "ventas" y otra de gastos por estado "estado", "gastos", ambas consultas usan group by ("estado"). Cuando hago la unión entre la izquierda y la derecha se une a dos consultas, obtengo algunas filas con ventas pero sin gastos, algunas más con gastos pero sin ventas, todo hasta este punto, pero también obtengo algunas con ambas ventas y gastos y una columna repetida de "estado" ... no es un gran problema pero no se siente bien ...
Jairo Lozano
1
@JairoLozano Las restricciones no son necesarias para realizar consultas. Aunque cuando las restricciones contienen consultas adicionales, devuelve la respuesta deseada que de otro modo no lo haría. Las restricciones no afectan qué unión completa en devoluciones para argumentos dados. El problema que describe es que la consulta que escribió es incorrecta. (Presumiblemente, el error común en el que las personas quieren algunas uniones, cada una posiblemente con una clave diferente, de algunas subconsultas, cada una posiblemente involucrando unión y / o agregación, pero intentan erróneamente hacer toda la unión, luego toda la agregación o agregación sobre agregaciones anteriores .)
philipxy

Respuestas:

669

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:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

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 UNIONoperador 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:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION ALL
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.id IS NULL
Pablo Santa Cruz
fuente
33
En realidad, lo que escribiste no es correcto. Porque cuando haces una UNIÓN, eliminarás duplicados y, a veces, cuando unas dos tablas diferentes, debería haber duplicados.
Pavle Lekic
158
Este es el ejemplo correcto:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Pavle Lekic
8
Entonces, la diferencia es que estoy haciendo una unión inclusiva a la izquierda y luego exclusiva a la derecha usando UNION ALL
Pavle Lekic
55
y ahora veo que lo dices tú mismo, lo siento. ¿Quizás podría actualizar su respuesta, dado que existe el caso de que se equivoca y que UNION ALL siempre será más eficiente?
ysth
10
@ypercube: si no hay filas duplicadas en t1y t2, 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 a FULL OUTER JOIN. Para obtener una emulación más fiel, necesitaríamos un UNION ALLoperador 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 .
spencer7593
351

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:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Uniones internas

Una unión interna, como esta:

SELECT *
FROM `t1`
INNER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

Solo obtendríamos registros que aparecen en ambas tablas, así:

1 Tim  1 Tim

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 JOINy RIGHT JOINson taquigrafía para LEFT OUTER JOINy RIGHT 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:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... 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:

1 Tim   1    Tim
2 Marta NULL NULL

Unión externa derecha

Una unión externa derecha, como esta:

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

... nos obtendría todos los registros de la tabla derecha, independientemente de si tienen una coincidencia en la tabla izquierda, como este:

1    Tim   1  Tim
NULL NULL  3  Katarina

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í:

1    Tim   1    Tim
2    Marta NULL NULL
NULL NULL  3    Katarina

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í:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`;

Puede pensar en a UNIONcomo 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 UNIONen MySQL eliminará los duplicados exactos: Tim aparecería en ambas consultas aquí, pero el resultado de las UNIONú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 una WHEREcláusula a la segunda consulta:

SELECT *
FROM `t1`
LEFT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`

UNION

SELECT *
FROM `t1`
RIGHT OUTER JOIN `t2` ON `t1`.`id` = `t2`.`id`
WHERE `t1`.`id` IS NULL;

Por otro lado, si quería ver duplicados por alguna razón, usted podría utilizar UNION ALL.

Nathan Long
fuente
44
Para MySQL, realmente desea evitar el uso de UNION en lugar de UNION ALL si no hay superposición (vea el comentario de Pavle arriba). Si pudiera agregar más información al respecto en su respuesta aquí, creo que sería la respuesta preferida para esta pregunta, ya que es más exhaustiva.
Garen
2
La recomendación del "colega gurú de la base de datos" es correcta. En términos del modelo relacional (todo el trabajo teórico realizado por Ted Codd y Chris Date), una consulta de la última forma emula una UNIÓN COMPLETA EXTERNA, porque combina dos conjuntos distintos. La segunda consulta no introduce "duplicados" ( filas ya devueltas por la primera consulta) que no serían producidas por a 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 a FULL OUTER JOIN, necesitamos una de las consultas para ser un anti-join.
spencer7593
1
@IstiaqueAhmed: el objetivo es emular una operación FULL OUTER JOIN. Necesitamos esa condición en la segunda consulta para que solo devuelva filas que no tengan una coincidencia (un patrón anti-unión). Sin esa condición, la consulta es una combinación externa ... devuelve filas que coinciden, así como las que no coinciden. Y las filas que coinciden ya fueron devueltas por la primera consulta. Si la segunda consulta devuelve esas mismas filas (nuevamente), hemos duplicado las filas y nuestro resultado no será equivalente a una UNIÓN COMPLETA EXTERNA.
spencer7593
1
@IstiaqueAhmed: Es cierto que una UNIONoperació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 emular a FULL JOIN b, el patrón correcto es (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
spencer7593
1
Respuesta muy concisa con una gran explicación. Gracias por esto.
Najeeb
35

El uso de una unionconsulta eliminará duplicados, y esto es diferente al comportamiento de full outer joinque nunca elimina ningún duplicado:

[Table: t1]                            [Table: t2]
value                                  value
-------                                -------
1                                      1
2                                      2
4                                      2
4                                      5

Este es el resultado esperado de full outer join:

value | value
------+-------
1     | 1
2     | 2
2     | 2
Null  | 5
4     | Null
4     | Null

Este es el resultado de usar lefty right Joincon union:

value | value
------+-------
Null  | 5 
1     | 1
2     | 2
4     | Null

[SQL Fiddle]

Mi consulta sugerida es:

select 
    t1.value, t2.value
from t1 
left outer join t2  
  on t1.value = t2.value
union all      -- Using `union all` instead of `union`
select 
    t1.value, t2.value
from t2 
left outer join t1 
  on t1.value = t2.value
where 
    t1.value IS NULL 

Resultado de la consulta anterior que es igual al resultado esperado:

value | value
------+-------
1     | 1
2     | 2
2     | 2
4     | NULL
4     | NULL
NULL  | 5

[SQL Fiddle]


@Steve Chambers : [De los comentarios, ¡muchas gracias!]
Nota: Esta puede ser la mejor solución, tanto para la eficiencia como para generar los mismos resultados que a 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 usarlo en UNION ALLlugar de simple UNION, lo que eliminaría los duplicados que quiero conservar. Esto puede ser significativamente más eficiente en grandes conjuntos de resultados, ya que no hay necesidad de ordenar y eliminar duplicados ".


Decidí agregar otra solución que proviene de la full outer joinvisualización y las matemáticas, no es mejor que la anterior pero es más legible:

La combinación externa completa significa (t1 ∪ t2): todo dentro t1o dentro t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: todo en ambos t1y t2más todos los t1que no están dentro t2y más todos los t2que no están en t1:

-- (t1 ∩ t2): all in both t1 and t2
select t1.value, t2.value
from t1 join t2 on t1.value = t2.value    
union all  -- And plus 
-- all in t1 that not exists in t2
select t1.value, null
from t1
where not exists( select 1 from t2 where t2.value = t1.value)    
union all  -- and plus
-- all in t2 that not exists in t1
select null, t2.value
from t2
where not exists( select 1 from t1 where t2.value = t1.value)

[SQL Fiddle]

shA.t
fuente
Estamos haciendo los mismos tiempos de remolque de tareas, si hay una subconsulta para t1 y t2, entonces mysql tiene que hacer la misma tarea más veces, ¿no es así? ¿Podemos eliminar esto usando un alias en esta situación?:
Kabir Hossain
Le sugiero que use algunas tablas temporales;).
shA.t
55
Este método parece ser la mejor solución, tanto para la eficiencia como para generar los mismos resultados que a 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 ".
Steve Chambers
2
@SteveChambers es demasiado tarde, pero gracias por tu comentario. Agregué tu comentario para luego responder a resaltado más, si no estás de acuerdo, retrocede;).
shA.t
No hay problema @ shA.t - OMI, esto realmente debería tener más votos a favor y / o ser la respuesta aceptada.
Steve Chambers
6

MySql no tiene la sintaxis FULL-OUTER-JOIN. Tienes que emular haciendo LEFT JOIN y RIGHT JOIN de la siguiente manera:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id

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 FROMy ONen la consulta. Por lo tanto, MySql Query Optimizer traduce la consulta original en lo siguiente:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id  
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id

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 ONcláusula, que es un predicado durante la unión , entonces usted podría querer echar un vistazo al diablo; que está en detalles

MySql query optimizer verifica rutinariamente los predicados si son rechazados por nulo . Definición y ejemplos de rechazo 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:

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t1
RIGHT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'

se traduce a lo siguiente por el Optimizador de consultas

SELECT * FROM t1
LEFT JOIN t2 ON t1.id = t2.id
WHERE t1.col1 = 'someValue'
UNION
SELECT * FROM t2
LEFT JOIN t1 ON t2.id = t1.id
WHERE t1.col1 = 'someValue'

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.

ARCA
fuente
4

En SQLite deberías hacer esto:

SELECT * 
FROM leftTable lt 
LEFT JOIN rightTable rt ON lt.id = rt.lrid 
UNION
SELECT lt.*, rl.*  -- To match column set
FROM rightTable rt 
LEFT JOIN  leftTable lt ON lt.id = rt.lrid
Rami Jamleh
fuente
¿Podemos usarlo? como: SELECT * FROM leftTable lt LEFT JOIN rightTable rt ON lt.id = rt.lrid UNION SELECT lt. *, rl. * - Para hacer coincidir el conjunto de columnas FROM leftTable lt RIGHT JOIN rightTable rt ON lt.id = rt.lrid ;
Kabir Hossain
sí, pero SQLite no admite combinaciones correctas, pero sí en MYSQL sí
Rami Jamleh
4

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 ):

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.Name = t2.Name;

El equivalente correcto es:

SELECT t1.*, t2.*
FROM (SELECT name FROM t1 UNION  -- This is intentionally UNION to remove duplicates
      SELECT name FROM t2
     ) n LEFT JOIN
     t1
     ON t1.name = n.name LEFT JOIN
     t2
     ON t2.name = n.name;

Si necesita que esto funcione con NULLvalores (que también pueden ser necesarios), utilice el NULLoperador de comparación seguro, en <=>lugar de =.

Gordon Linoff
fuente
3
Esta suele ser una buena solución, pero puede dar resultados diferentes que FULL OUTER JOINcuando la namecolumna es nula. La union allconsulta 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.
fthiella
@fthiella. . . Ese es un buen punto. Ajusté la respuesta.
Gordon Linoff el
1
bien, pero el operador de comparación nulo-seguro hará que la unión sea exitosa, lo cual es diferente del comportamiento de la unión externa completa en caso de que tenga nombres nulos tanto en t1 como en t2
fthiella
@fthiella. . . Tendré que pensar en la mejor manera de hacer esto. Pero dado lo incorrecta que es la respuesta aceptada, casi cualquier cosa está más cerca de la respuesta correcta. (Esa respuesta es incorrecta si hay varias claves a cada lado).
Gordon Linoff el
1
sí, la respuesta aceptada es incorrecta, como una solución general, creo que es correcto de usar 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.
fthiella
3

Se modificó la consulta de shA.t para obtener más claridad:

-- t1 left join t2
SELECT t1.value, t2.value
FROM t1 LEFT JOIN t2 ON t1.value = t2.value   

    UNION ALL -- include duplicates

-- t1 right exclude join t2 (records found only in t2)
SELECT t1.value, t2.value
FROM t1 RIGHT JOIN t2 ON t1.value = t2.value
WHERE t2.value IS NULL 
a20
fuente
3

Puedes hacer lo siguiente:

(SELECT 
    *
FROM
    table1 t1
        LEFT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t2.id IS NULL)
UNION ALL
 (SELECT 
    *
FROM
    table1 t1
        RIGHT JOIN
    table2 t2 ON t1.id = t2.id
WHERE
    t1.id IS NULL);
lolo
fuente
1

¿Qué dijiste sobre la solución Cross join ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;
Super Mario
fuente
2
No, esta es una unión cruzada. Emparejará cada fila en t1 con cada fila en t2, produciendo el conjunto de todas las combinaciones posibles, con select (select count(*) from t1) * (select count(*) from t2))filas en el conjunto de resultados.
Marc L.
Si bien este código puede responder la pregunta, proporcionar un contexto adicional sobre cómo y por qué resuelve el problema mejoraría el valor a largo plazo de la respuesta.
Alexander
¿Qué adición puede ser útil? tal vez en ejemplo?
Super Mario
0
SELECT
    a.name,
    b.title
FROM
    author AS a
LEFT JOIN
    book AS b
    ON a.id = b.author_id
UNION
SELECT
    a.name,
    b.title
FROM
    author AS a
RIGHT JOIN
    book AS b
    ON a.id = b.author_id
Alex Pliutau
fuente
0

También es posible, pero debe mencionar los mismos nombres de campo en select.

SELECT t1.name, t2.name FROM t1
LEFT JOIN t2 ON t1.id = t2.id
UNION
SELECT t1.name, t2.name FROM t2
LEFT JOIN t1 ON t1.id = t2.id
alamelu
fuente
Esto es solo duplicar los resultados de una unión izquierda.
Mateo leyó el
-1

Arreglo la respuesta, y las obras incluyen todas las filas (según la respuesta de Pavle Lekic)

    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    WHERE b.`key` is null
    )
    UNION ALL
    (
    SELECT a.* FROM tablea a
    LEFT JOIN tableb b ON a.`key` = b.key
    where  a.`key` = b.`key`
    )
    UNION ALL
    (
    SELECT b.* FROM tablea a
    right JOIN tableb b ON b.`key` = a.key
    WHERE a.`key` is null
    );
Rubén Ruíz
fuente
No, este es un tipo de unión "solo externa", que solo devolverá las filas de las tableaque no coinciden tableby viceversa. Intenta hacerlo UNION ALL, lo que solo funcionaría si estas dos tablas tienen columnas ordenadas de manera equivalente, lo que no está garantizado.
Marc L.
funciona, creo en la base de datos temporal tablea (1,2,3,4,5,6) y tableb (4,5,6,7,8,9) sus filas tienen 3 cols "id", "number" y "name_number" como texto, y las obras en resultado solo tienen (1,2,3,7,8,9)
Rubén Ruíz
1
Esa no es una unión externa. Una unión externa también incluye los miembros coincidentes.
Marc L.
esa nueva oración tiene todos los resultados 1,2, ..., 9
Rubén Ruíz
-2

Responder:

SELECT * FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;

Se puede recrear de la siguiente manera:

 SELECT t1.*, t2.* 
 FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp
 LEFT JOIN t1 ON t1.id = tmp.id
 LEFT JOIN t2 ON t2.id = tmp.id;

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:

 WITH cte_t1 AS
 (
       SELECT 1 AS id1
       UNION ALL SELECT 2
       UNION ALL SELECT 5
       UNION ALL SELECT 6
       UNION ALL SELECT 6
 ),
cte_t2 AS
(
      SELECT 3 AS id2
      UNION ALL SELECT 4
      UNION ALL SELECT 5
      UNION ALL SELECT 6
      UNION ALL SELECT 6
)
SELECT  *  FROM  cte_t1 t1 FULL OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2;

This gives us this answer:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

La solución UNION:

SELECT  * FROM  cte_t1 t1 LEFT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2
UNION    
SELECT  * FROM cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

Da una respuesta incorrecta:

 id1  id2
NULL  3
NULL  4
1  NULL
2  NULL
5  5
6  6

La solución UNION ALL:

SELECT  * FROM cte_t1 t1 LEFT OUTER join cte_t2 t2 ON t1.id1 = t2.id2
UNION ALL
SELECT  * FROM  cte_t1 t1 RIGHT OUTER JOIN cte_t2 t2 ON t1.id1 = t2.id2

También es incorrecto.

id1  id2
1  NULL
2  NULL
5  5
6  6
6  6
6  6
6  6
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

Mientras que esta consulta:

SELECT t1.*, t2.*
FROM (SELECT * FROM t1 UNION SELECT name FROM t2) tmp 
LEFT JOIN t1 ON t1.id = tmp.id 
LEFT JOIN t2 ON t2.id = tmp.id;

Da lo siguiente:

id1  id2
1  NULL
2  NULL
NULL  3
NULL  4
5  5
6  6
6  6
6  6
6  6

El orden es diferente, pero por lo demás coincide con la respuesta correcta.

Angelos
fuente
Eso es lindo, pero tergiversa la UNION ALLsolución. Además, presenta una solución UNIONque sería más lenta en tablas de origen grandes debido a la desduplicación requerida. Finalmente, no se compilaría, porque el campo idno existe en la subconsulta tmp.
Marc L.
Nunca hice un reclamo sobre la velocidad, y el OP tampoco mencionó nada sobre la velocidad. Suponiendo que UNION ALL (no confía, especifique cuál) y ambos dan la respuesta correcta, si quisiéramos afirmar que uno es más rápido, tendríamos que proporcionar puntos de referencia, y eso sería desviarnos del OP pregunta.
Angelos
En cuanto a la observación acerca de que la identificación no está en la subconsulta, corregí el error tipográfico. Gracias por señalarlo. Su afirmación de tergiversaciones es vaga; si tal vez pudiera proporcionar más información, puedo abordarlo. En su observación final sobre la ternura, no tengo ningún comentario, prefiero centrarme en la lógica del sql.
Angelos
3
Tergiversa: "La UNION ALLsolució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 en UNION 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.
Marc L.
-3

El estándar SQL dice full join onque las inner join onfilas de la union alltabla izquierda no coinciden filas extendidas por nulos union allfilas de tabla derecha extendidas por nulos. Es decir, inner join onfilas union allfilas left join onpero no inner join on union allfilas right join onpero no inner join on.

Es decir, left join onfilas union all right join onfilas no adentro inner join on. O si sabe que su inner join onresultado no puede tener un valor nulo en una columna de tabla derecha en particular, entonces las " right join onfilas no incluidas inner join on" son filas right join oncon la oncondición extendida por andesa columna is null.

Es decir, filas igualmente right join on union allapropiadas left join on.

De Cuál es la diferencia entre “INNER JOIN” y “OUTER JOIN”? :

(SQL Standard 2006 SQL / Foundation 7.7 Reglas de sintaxis 1, Reglas generales 1 b, 3 c & d, 5 b.)

filipina
fuente