Como fazer uma junção externa completa no MySQL?

654

Eu quero fazer uma junção externa completa no MySQL. Isso é possível? Uma junção externa completa é suportada pelo MySQL?

Spencer
fonte
2
possível duplicata do MySQL completa associação externa erro de sintaxe
Joe Stefanelli
4
Esta questão tem melhores respostas
Julio Marins
Cuidado com as respostas aqui. O padrão SQL diz que a junção completa é a junção interna nas linhas. Todas as linhas da tabela esquerda sem correspondência estendidas por nulos. A maioria das respostas aqui estão erradas (veja os comentários) e as que não estão erradas não lidam com o caso geral. Mesmo que haja muitas votações (injustificadas). (Veja a minha resposta.)
philipxy
E quando você tenta ingressar por chaves não primárias / colunas agrupadas? como eu tenho uma consulta de vendas por estado "estado", "vende" e outra de despesas por estado "estado", "despesas", ambas as consultas usam o grupo por ("estado"). Quando faço a união entre a esquerda e a direita, entre duas consultas, recebo algumas linhas com vendas, mas sem despesas, mais algumas com despesas, mas sem vendas, tudo até esse ponto, mas também recebo algumas com ambas. vende e despesas e uma coluna repetida "estado" ... não muito de um problema, mas não se sente bem ...
Jairo Lozano
1
@JairoLozano Restrições não são necessárias para consulta. Embora quando as restrições mantêm consultas extras, retorne a resposta desejada que de outra forma não seria. As restrições não afetam a junção completa dos retornos de determinados argumentos. O problema que você descreve é ​​que a consulta que você escreveu é a consulta errada. (Presumivelmente, o erro comum em que as pessoas desejam algumas junções, cada uma possivelmente envolvendo uma chave diferente, de algumas subconsultas, cada uma possivelmente envolvendo junção e / ou agregação, mas tentam erroneamente fazer toda a junção e depois a agregação ou agregação das agregações anteriores .)
philipxy

Respostas:

669

Você não possui JOYS FULL no MySQL, mas com certeza pode imitá-los .

Para um código SAMPLE transcrito desta questão SO, você tem:

com duas tabelas 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

A consulta acima funciona para casos especiais em que uma operação FULL OUTER JOIN não produziria nenhuma linha duplicada. A consulta acima depende do UNIONoperador set para remover linhas duplicadas introduzidas pelo padrão de consulta. Podemos evitar a introdução de linhas duplicadas usando um padrão anti-junção para a segunda consulta e, em seguida, usar um operador de conjunto UNION ALL para combinar os dois conjuntos. No caso mais geral, onde um JOGO EXTERNO CHEIO retornaria linhas duplicadas, podemos fazer isso:

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
fonte
33
Na verdade, o que você escreveu não está correto. Porque quando você faz um UNION, você remove duplicatas e, às vezes, quando junta duas tabelas diferentes, deve haver duplicatas.
Pavle Lekic
158
Este é o exemplo correto:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Pavle Lekic 19/03/2013
8
Assim, a diferença é que eu estou fazendo uma esquerda Inclusive se juntar e, em seguida, direito exclusivo usando UNION ALL
Pavle Lekic
5
e agora vejo que você diz isso, desculpe. Talvez você possa atualizar sua resposta, dado que existe um caso errado e que o UNION ALL sempre será mais eficiente?
ysth 31/03
10
@ ypercube: se não houver linhas duplicadas em t1e t2, a consulta nesta resposta retornará um conjunto de resultados que emula a junção externa completa . Porém, no caso mais geral, por exemplo, a lista SELECT não contém colunas / expressões suficientes para tornar as linhas retornadas únicas; esse padrão de consulta é insuficiente para reproduzir o conjunto que seria produzido por a FULL OUTER JOIN. Para obter uma emulação mais fiel, precisaríamos de um UNION ALLoperador set e uma das consultas precisaria de um padrão anti-junção . O comentário de Pavle Lekic (acima) fornece o padrão de consulta correto .
Spencer7593
351

A resposta que Pablo Santa Cruz deu está correta; no entanto, caso alguém tropece nesta página e deseje mais esclarecimentos, aqui está um detalhamento detalhado.

Tabelas de exemplo

Suponha que tenhamos as seguintes tabelas:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Junções internas

Uma junção interna, assim:

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

Nos levaria apenas os registros que aparecem nas duas tabelas, assim:

1 Tim  1 Tim

As junções internas não têm uma direção (como esquerda ou direita) porque são explicitamente bidirecionais - exigimos uma correspondência dos dois lados.

Junções externas

As junções externas, por outro lado, são para localizar registros que podem não ter uma correspondência na outra tabela. Como tal, você deve especificar qual lado da associação pode ter um registro ausente.

LEFT JOINe RIGHT JOINsão abreviação de LEFT OUTER JOINe RIGHT OUTER JOIN; Usarei seus nomes completos abaixo para reforçar o conceito de junções externas versus junções internas.

Junção externa esquerda

Uma junção externa esquerda, assim:

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

... nos forneceria todos os registros da tabela esquerda, independentemente de eles corresponderem ou não à tabela correta, assim:

1 Tim   1    Tim
2 Marta NULL NULL

Junção externa direita

Uma junção externa direita, assim:

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

... nos obteria todos os registros da tabela da direita, independentemente de haver ou não uma correspondência na tabela da esquerda, assim:

1    Tim   1  Tim
NULL NULL  3  Katarina

Junção externa completa

Uma junção externa completa nos forneceria todos os registros de ambas as tabelas, independentemente de terem ou não correspondência na outra tabela, com NULLs nos dois lados onde não há correspondência. O resultado ficaria assim:

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

No entanto, como Pablo Santa Cruz apontou, o MySQL não suporta isso. Podemos emular isso fazendo uma UNIÃO de uma junção esquerda e uma junção direita, assim:

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`;

Você pode pensar UNIONno significado de "executar ambas as consultas e empilhar os resultados uns sobre os outros"; algumas das linhas virão da primeira consulta e outras da segunda.

Deve-se notar que a UNIONno MySQL eliminará duplicatas exatas: Tim apareceria nas duas consultas aqui, mas o resultado da UNIONúnica lista dele uma vez. Meu colega de guru de banco de dados considera que esse comportamento não deve ser invocado. Para ser mais explícito, podemos adicionar uma WHEREcláusula à 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 outro lado, se você quiser ver duplicatas por algum motivo, poderá usar UNION ALL.

Nathan Long
fonte
4
Para o MySQL, você realmente deseja evitar o uso de UNION em vez de UNION ALL se não houver sobreposição (veja o comentário de Pavle acima). Se você puder adicionar mais algumas informações nesse sentido em sua resposta aqui, acho que seria a resposta preferida para essa pergunta, pois é mais completa.
Garen
2
A recomendação do "colega guru do banco de dados" está correta. Em termos do modelo relacional (todo o trabalho teórico realizado por Ted Codd e Chris Date), uma consulta da última forma emula uma junção externa completa, porque combina dois conjuntos distintos. A segunda consulta não apresenta "duplicatas" ( linhas já retornadas pela primeira consulta) que não seriam produzidas por a FULL OUTER JOIN. Não há nada errado em fazer consultas dessa maneira e usar o UNION para remover essas duplicatas. Mas, para realmente replicar um FULL OUTER JOIN, precisamos de uma das consultas para ser uma anti-junção.
Spencer7593
1
@IstiaqueAhmed: o objetivo é emular uma operação FULL OUTER JOIN. Precisamos dessa condição na segunda consulta para que ela retorne apenas linhas que não tenham uma correspondência (um padrão de anti-junção). Sem essa condição, a consulta é uma junção externa ... ela retorna as linhas correspondentes e as que não correspondem. E as linhas correspondentes foram retornadas pela primeira consulta. Se a segunda consulta retornar as mesmas linhas (novamente), duplicamos as linhas e nosso resultado não será equivalente a uma junção externa completa.
spencer7593
1
@IstiaqueAhmed: É verdade que uma UNIONoperação removerá essas duplicatas; mas também remove TODAS as linhas duplicadas, incluindo linhas duplicadas que seriam retornadas por uma junção externa completa. Para emular a FULL JOIN b, o padrão correto é (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
spencer7593
1
Resposta muito concisa com uma ótima explicação. Obrigado por isso.
Najeeb
35

O uso de uma unionconsulta removerá duplicatas, e isso é diferente do comportamento de full outer joinnunca remover duplicatas:

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

Este é o resultado esperado de full outer join:

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

Este é o resultado do uso lefte right Joincom union:

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

[SQL Fiddle]

Minha consulta sugerida é:

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 da consulta acima igual ao resultado esperado:

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

[SQL Fiddle]


@ Steve Chambers : [Dos comentários, com muito obrigado!]
Nota: Essa pode ser a melhor solução, tanto para eficiência quanto para gerar os mesmos resultados que a FULL OUTER JOIN. Esta postagem no blog também explica bem - para citar o Método 2: "Isso manipula linhas duplicadas corretamente e não inclui nada que não deveria. É necessário usar em UNION ALLvez de simples UNION, o que eliminaria as duplicatas que eu quero manter. Isso pode ser significativamente mais eficiente em grandes conjuntos de resultados, pois não há necessidade de classificar e remover duplicatas ".


Eu decidi adicionar outra solução que vem da full outer joinvisualização e matemática, não é melhor que acima, mas mais legível:

Junção externa completa significa (t1 ∪ t2): tudo dentro t1ou dentro t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: tudo dentro t1e t2mais tudo o t1que não está dentro t2e mais tudo o t2que não está dentro 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
fonte
Estamos fazendo a mesma tarefa vezes de reboque. Se houver subconsulta para t1 e t2, o mysql precisará executar a mesma tarefa mais vezes, não é? Podemos remover isso usando o alias nesta situação?::
Kabir Hossain
Eu sugiro que você use algumas tabelas temporárias;).
shA.t
5
Esse método parece ser a melhor solução, tanto para eficiência quanto para gerar os mesmos resultados que a FULL OUTER JOIN. Esta postagem no blog também explica bem - para citar o Método 2: "Isso manipula linhas duplicadas corretamente e não inclui nada que não deveria. É necessário usar UNION ALL em vez de UNION simples, o que eliminaria as duplicatas que eu quero Isso pode ser significativamente mais eficiente em grandes conjuntos de resultados, pois não há necessidade de classificar e remover duplicatas ".
22616 Steve Chambers
2
@SteveChambers é tarde demais, mas obrigado pelo seu comentário. Eu adicionei o seu comentário para responder a mais destacado. Se você não concordar, reverta-o;).
shA.t
Não há problema @ shA.t - OMI deve realmente ter mais votos positivos e / ou ser a resposta aceita.
Steve Chambers
6

O MySql não possui sintaxe FULL-OUTER-JOIN. Você deve emular executando ESQUERDA JOIN e DIREITA JOIN da seguinte maneira:

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

Mas o MySql também não possui uma sintaxe RIGHT JOIN. De acordo com a simplificação da junção externa do MySql , a junção direita é convertida na junção esquerda equivalente alternando t1 e t2 na cláusula FROMe ONna consulta. Assim, o MySql Query Optimizer converte a consulta original no seguinte -

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

Agora, não há nenhum problema em escrever a consulta original como está, mas digamos que se você tiver predicados como a cláusula WHERE, que é um predicado antes da junção ou um predicado AND na ONcláusula, que é um predicado durante a junção , então você pode querer dar uma olhada no diabo; que está em detalhes.

O otimizador de consultas do MySql rotineiramente verifica os predicados se eles são nulos . Definição e exemplos rejeitados por nulo Agora, se você tiver feito o DIREITO JOIN, mas com o predicado WHERE na coluna de t1, poderá correr o risco de encontrar um cenário rejeitado por nulo .

Por exemplo, a consulta a seguir -

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'

é traduzido para o seguinte pelo Query Optimizer-

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'

Portanto, a ordem das tabelas mudou, mas o predicado ainda é aplicado a t1, mas agora está na cláusula 'ON'. Se t1.col1 for definido como NOT NULL coluna, essa consulta será rejeitada por nulo .

Qualquer junção externa (esquerda, direita, cheia) que seja rejeitada por nulo é convertida em uma junção interna pelo MySql.

Portanto, os resultados que você pode esperar podem ser completamente diferentes do que o MySql está retornando. Você pode pensar que é um bug com o RIGHT JOIN do MySql, mas isso não está certo. É assim que o otimizador de consultas do MySql funciona. Portanto, o desenvolvedor responsável deve prestar atenção a essas nuances quando estiver construindo a consulta.

ARCA
fonte
4

No SQLite, você deve fazer isso:

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
fonte
Podemos usá-lo? como: SELECT * FROM tabela esquerda ESQUERDA JOIN tabela direita rt ON lt.id = rt.lrid UNIÃO SELEÇÃO lt. *, rl. * - Para corresponder ao conjunto de colunas FROM tabela esquerda ;
Kabir Hossain
sim, mas SQLite não suporta direito junta-se, mas sim em sim MYSQL
Rami Jamleh
4

Nenhuma das respostas acima está realmente correta, porque elas não seguem a semântica quando há valores duplicados.

Para uma consulta como (desta duplicata ):

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

O equivalente correto é:

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;

Se você precisar que isso funcione com NULLvalores (o que também pode ser necessário), use o NULLoperador de comparação -safe, em <=>vez de =.

Gordon Linoff
fonte
3
isso geralmente é uma boa solução, mas pode fornecer resultados diferentes de a FULL OUTER JOINsempre que a namecoluna for nula. A union allconsulta com padrão anti-junção deve reproduzir o comportamento da junção externa corretamente, mas qual solução é mais apropriada depende do contexto e das restrições ativas nas tabelas.
Fthiella 31/03/19
@fthiella. . . Essa é uma boa opinião. Eu ajustei a resposta.
Gordon Linoff 31/03
1
ok, mas o operador de comparação nulo-safe vai fazer a junção ter sucesso, que é diferente do que a junção externa completa comportamento no caso de você ter nomes nulos, tanto em t1 e t2 em
fthiella
@fthiella. . . Vou ter que pensar na melhor maneira de fazer isso. Mas, dada a resposta errada, quase tudo está mais próximo da resposta certa. (Essa resposta é simplesmente errado se houver várias chaves de cada lado.)
Gordon Linoff
1
Sim, a resposta aceita está errada, como uma solução geral, acho que é correto usar union all, mas essa resposta perde um padrão de anti-junção na primeira ou na segunda consulta que manterá as duplicatas existentes, mas impede a adição de novas. Dependendo do contexto, outras soluções (como esta) podem ser mais apropriadas.
Fthiella #
3

Consulta do shA.t modificada para maior clareza:

-- 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
fonte
3

Você pode fazer o seguinte:

(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
fonte
1

o que você disse sobre a solução de junção cruzada ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;
Super Mario
fonte
2
Não, esta é uma junção cruzada. Ele corresponderá todas as linhas em t1 a todas as linhas em t2, produzindo o conjunto de todas as combinações possíveis, com select (select count(*) from t1) * (select count(*) from t2))linhas no conjunto de resultados.
Marc L.
Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e por que resolve o problema melhoraria o valor a longo prazo da resposta.
27418 Alexander Alexander
Qual adição pode ser útil? talvez um exemplo?
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
fonte
0

Também é possível, mas você deve mencionar os mesmos nomes de campo em 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
fonte
Isso está apenas duplicando os resultados de uma junção esquerda.
Mateus Leia
-1

Corrijo a resposta e os trabalhos incluem todas as linhas (com base na resposta 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
fonte
Não, este é um tipo de junção "somente externa", que retornará apenas as linhas tableaque não possuem correspondência tablebe vice-versa. Você tenta UNION ALL, o que só funcionaria se essas duas tabelas tivessem colunas ordenadas equivalentemente, o que não é garantido.
Marc L.
funciona, eu crio no banco de dados temp tablea (1,2,3,4,5,6) e tableb (4,5,6,7,8,9) suas linhas possuem 3 cols "id", "number" e "name_number" como texto, e trabalha em resultado só têm (1,2,3,7,8,9)
Rubén Ruíz
1
Isso não é uma junção externa. Uma junção externa também inclui os membros correspondentes.
Marc L.
essa nova sentença tem todos os resultados 1,2, ..., 9
Rubén Ruíz 02/08
-2

Responda:

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

Pode ser recriado da seguinte maneira:

 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;

O uso de uma resposta UNION ou UNION ALL não cobre o caso de borda em que as tabelas base têm entradas duplicadas.

Explicação:

Há um caso extremo que uma UNION ou UNION ALL não pode cobrir. Nós não podemos testar isso no mysql, pois ele não suporta JOINS EXTERIORES COMPLETOS, mas podemos ilustrar isso em um banco de dados que o suporta:

 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

A solução 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

Dá uma resposta incorreta:

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

A solução 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

Também está incorreto.

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

Considerando 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;

Fornece o seguinte:

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

A ordem é diferente, mas corresponde à resposta correta.

Angelos
fonte
Isso é engraçado, mas deturpa a UNION ALLsolução. Além disso, ele apresenta uma solução UNIONque seria mais lenta em grandes tabelas de origem devido à deduplicação necessária. Finalmente, não seria compilado, porque o campo idnão existe na subconsulta tmp.
Marc L.
Eu nunca fiz uma reivindicação sobre velocidade, e o OP também não mencionou nada sobre velocidade. Assumindo que UNION ALL (você não confia em especificar qual), e isso fornece a resposta correta, se quiséssemos afirmar que uma é mais rápida, precisaríamos fornecer referências e isso seria desviado do OP questão.
Angelos
Quanto à observação sobre o id não estar na subconsulta, eu corrigi o erro de digitação - obrigado por apontá-lo. Sua alegação de falsas declarações é vaga. Se você puder fornecer mais informações, posso resolver isso. Na sua observação final sobre fofura, não tenho nenhum comentário, prefiro focar na lógica do sql.
Angelos
3
Representa UNION ALLincorretamente : "A solução: ... Também está incorreta." O código que você apresenta deixa de fora a exclusão de interseção da join-right ( where t1.id1 is null) que deve ser fornecida no UNION ALL. Ou seja, sua solução supera todas as outras, somente quando uma dessas outras soluções é implementada incorretamente. Sobre "fofura", ponto em questão. Isso foi gratuito, minhas desculpas.
27478 Marc
-3

O padrão SQL diz full join oné inner join onlinhas union allímpares linhas da tabela esquerda estendidos por nulos union alllinhas da tabela direita estendida por valores nulos. Ou seja, inner join onlinhas union alllinhas, left join onmas não inner join on union alllinhas, right join onmas nãoinner join on .

Ou seja, left join onlinhas union all right join onlinhas fora inner join on. Ou, se você souber que seu inner join onresultado não pode ter nulo em uma coluna específica da tabela à direita, " right join onlinhas que não inner join onestão" são linhas right join oncom a oncondição estendida por andessa coluna is null.

Ou seja, linhas igualmente right join on union allapropriadas left join on.

De Qual é a diferença entre "INNER JOIN" e "OUTER JOIN"? :

(Regras de sintaxe 1 do SQL Standard 2006 SQL / Foundation 7.7, Regras gerais 1 b, 3 c & d, 5 b.)

philipxy
fonte