Come fare un JOU COMPLETO ESTERNO in MySQL?


654

Voglio fare un Full Outer Join in MySQL. È possibile? Un join esterno completo è supportato da MySQL?



4
Questa domanda ha risposte migliori
Julio Marins,

Fai attenzione alle risposte qui. Lo standard SQL afferma che il join completo su è join interno su righe unione tutte le righe di tabella sinistra non corrispondenti estese da null unione di tutte le righe di tabella destra estese da null. La maggior parte delle risposte qui sono errate (vedi i commenti) e quelle che non lo sono non gestiscono il caso generale. Anche se ci sono molti voti (ingiustificati). (Vedi la mia risposta.)
philipxy,

Che dire di quando si tenta di unirsi con chiavi non primarie / colonne raggruppate? come se avessi una query di vendite per stato "stato", "vendite" e un'altra delle spese per stato "stato", "spese", entrambe le query utilizzano il gruppo per ("stato"). Quando faccio l'unione tra la sinistra e la destra si unisce a due query ottengo alcune righe con vendite ma nessuna spesa, alcune altre con spese ma nessuna vendita, tutto fino a questo punto, ma ne ottengo anche alcune con entrambe vendite e spese e una ripetuta colonna "stato" ... non c'è molto problema ma non sembra giusto ...
Jairo Lozano

1
I vincoli di @JairoLozano non sono necessari per interrogare. Anche se quando i vincoli trattengono query extra restituiscono la risposta desiderata che altrimenti non lo farebbe. I vincoli non influiscono sull'unione completa sui rendimenti per determinati argomenti. Il problema che descrivi è che la query che hai scritto è la query sbagliata. (Presumibilmente l'errore comune in cui le persone vogliono alcuni join, ognuno dei quali potrebbe comportare una chiave diversa, di alcune subquery, ciascuno dei quali potrebbe comportare join e / o aggregazione, ma cercano erroneamente di fare tutto il join quindi tutto l'aggregazione o aggregare rispetto alle aggregazioni precedenti .)
philipxy

Risposte:


669

Non hai JOIN COMPLETI su MySQL, ma puoi sicuramente emularli .

Per un codice SAMPLE trascritto da questa domanda SO hai:

con due tabelle 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 query sopra funziona per casi speciali in cui un'operazione FULL OUTER JOIN non produce righe duplicate. La query sopra dipende UNIONdall'operatore set per rimuovere le righe duplicate introdotte dal modello di query. È possibile evitare di introdurre righe duplicate utilizzando un modello anti-join per la seconda query, quindi utilizzare un operatore di set UNION ALL per combinare i due set. Nel caso più generale, in cui un JOEN FULL OUTER restituisce righe duplicate, possiamo farlo:

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

33
In realtà la cosa che hai scritto non è corretta. Perché quando fai un'UNIONE rimuoverai i duplicati, e talvolta quando unirai a due diverse tabelle dovrebbero esserci dei duplicati.
Pavle Lekic,

158
Questo è l'esempio corretto:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Pavle Lekic

8
Quindi la differenza è che sto facendo un join inclusivo sinistro e poi esclusivo esclusivo usando UNION ALL
Pavle Lekic

5
e vedo ora che lo dici tu stesso, scusa. Forse potresti aggiornare la tua risposta, dato che in questo caso c'è un errore e che UNION ALL sarà sempre più efficiente?
ysth

10
@ypercube: se non sono presenti righe duplicate in t1e t2, la query in questa risposta restituisce un gruppo di risultati che emula FULL OUTER JOIN. Ma nel caso più generale, ad esempio, l'elenco SELECT non contiene colonne / espressioni sufficienti per rendere uniche le righe restituite, quindi questo modello di query non è sufficiente per riprodurre l'insieme che sarebbe prodotto da a FULL OUTER JOIN. Per ottenere un'emulazione più fedele, avremmo bisogno di un UNION ALLoperatore impostato e una delle query avrebbe bisogno di un modello anti-join . Il commento di Pavle Lekic (sopra) fornisce il modello di query corretto .
spencer7593,

351

La risposta che Pablo Santa Cruz ha dato è corretta; tuttavia, nel caso in cui qualcuno si fosse imbattuto in questa pagina e volesse maggiori chiarimenti, ecco un dettaglio dettagliato.

Tabelle di esempio

Supponiamo di avere le seguenti tabelle:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Inner Joins

Un join interno, come questo:

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

Ci procurerebbe solo i record che appaiono in entrambe le tabelle, in questo modo:

1 Tim  1 Tim

I join interni non hanno una direzione (come sinistra o destra) perché sono esplicitamente bidirezionali: è necessaria una corrispondenza su entrambi i lati.

Join esterni

I join esterni, d'altra parte, servono per trovare record che potrebbero non avere una corrispondenza nell'altra tabella. Pertanto, è necessario specificare a quale parte del join è consentito avere un record mancante.

LEFT JOINe RIGHT JOINsono una scorciatoia per LEFT OUTER JOINe RIGHT OUTER JOIN; Userò i loro nomi completi qui sotto per rafforzare il concetto di join esterni rispetto a join interni.

Join esterno sinistro

Un join esterno sinistro, in questo modo:

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

... ci procurerebbe tutti i record dalla tabella di sinistra indipendentemente dal fatto che abbiano o meno una corrispondenza nella tabella di destra, in questo modo:

1 Tim   1    Tim
2 Marta NULL NULL

Join esterno destro

Un join esterno destro, in questo modo:

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

... ci prenderebbe tutti i record dalla tabella a destra indipendentemente dal fatto che abbiano o meno una corrispondenza nella tabella a sinistra, in questo modo:

1    Tim   1  Tim
NULL NULL  3  Katarina

Join esterno completo

Un join esterno completo ci fornirebbe tutti i record di entrambe le tabelle, indipendentemente dal fatto che abbiano o meno una corrispondenza nell'altra tabella, con NULL su entrambi i lati in cui non esiste corrispondenza. Il risultato sarebbe simile al seguente:

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

Tuttavia, come sottolineato da Pablo Santa Cruz, MySQL non lo supporta. Possiamo emularlo facendo un'UNIONE di un join sinistro e un join destro, in questo modo:

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

Puoi pensare a un UNIONsignificato come "esegui entrambe queste query, quindi impila i risultati uno sopra l'altro"; alcune delle righe verranno dalla prima query e alcune dalla seconda.

Va notato che a UNIONin MySQL eliminerà i duplicati esatti: Tim apparirebbe in entrambe le query qui, ma il risultato UNIONdell'unica lo elenca una volta. Il mio collega guru del database ritiene che questo comportamento non debba essere invocato. Quindi, per essere più espliciti al riguardo, potremmo aggiungere una WHEREclausola alla seconda query:

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;

D'altra parte, se volessi vedere i duplicati per qualche motivo, potresti usare UNION ALL.


4
Per MySQL vuoi davvero evitare di usare UNION invece di UNION ALL se non ci sono sovrapposizioni (vedi il commento di Pavle sopra). Se potessi aggiungere altre informazioni in tal senso nella tua risposta qui, penso che sarebbe la risposta preferita per questa domanda in quanto è più approfondita.
Garen,

2
La raccomandazione del "collega guru del database" è corretta. In termini di modello relazionale (tutto il lavoro teorico svolto da Ted Codd e Chris Date), una query dell'ultimo modulo emula un FULL OUTER JOIN, perché combina due set distinti, la seconda query non introduce "duplicati" ( righe già restituite dalla prima query) che non verrebbero prodotte da a FULL OUTER JOIN. Non c'è niente di sbagliato nel fare query in quel modo e nell'usare UNION per rimuovere quei duplicati. Ma per replicare davvero un FULL OUTER JOIN, abbiamo bisogno di una delle query per essere un anti-join.
spencer7593,

1
@IstiaqueAhmed: l'obiettivo è emulare un'operazione FULL OUTER JOIN. Abbiamo bisogno di quella condizione nella seconda query in modo che restituisca solo le righe che non hanno una corrispondenza (un modello anti-join). Senza questa condizione, la query è un join esterno ... restituisce le righe corrispondenti e quelle senza corrispondenza. E le righe corrispondenti sono già state restituite dalla prima query. Se la seconda query restituisce quelle stesse righe (di nuovo), abbiamo duplicato le righe e il nostro risultato non sarà equivalente a un JOEN FULL OUTER.
spencer7593,

1
@IstiaqueAhmed: è vero che UNIONun'operazione rimuoverà quei duplicati; ma rimuove anche TUTTE le righe duplicate, incluse le righe duplicate che verrebbero restituite da un FULL OUTER JOIN. Per emulare a FULL JOIN b, il modello corretto è (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
spencer7593,

1
Risposta molto concisa con una grande spiegazione. Grazie per questo.
Najeeb,

35

L'uso di una unionquery rimuoverà i duplicati, e questo è diverso dal comportamento full outer joinche non rimuove mai alcun duplicato:

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

Questo è il risultato atteso di full outer join:

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

Questo è il risultato dell'utilizzo lefte right Joincon union:

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

[SQL Fiddle]

La mia domanda suggerita è:

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 

Risultato della query precedente uguale al risultato previsto:

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

[SQL Fiddle]


@Steve Chambers : [Dai commenti, con molte grazie!]
Nota: questa potrebbe essere la soluzione migliore, sia per efficienza che per generare gli stessi risultati di a FULL OUTER JOIN. Questo post sul blog lo spiega anche bene - per citare dal Metodo 2: "Questo gestisce correttamente le righe duplicate e non include nulla che non dovrebbe. È necessario utilizzare al UNION ALLposto di plain UNION, che eliminerebbe i duplicati che voglio conservare. Questo potrebbe essere significativamente più efficiente su grandi set di risultati, poiché non è necessario ordinare e rimuovere i duplicati ".


Ho deciso di aggiungere un'altra soluzione che viene dalla full outer joinvisualizzazione e dalla matematica, non è meglio di quanto sopra ma più leggibile:

Un join esterno completo significa (t1 ∪ t2): all in t1o in t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: all in entrambi t1e t2più all in t1che non sono in t2e plus all in t2che non sono in 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]


Stiamo facendo gli stessi tempi di rimorchio dell'attività, Se ci sono sottoquery per t1 e t2 allora mysql deve fare lo stesso compito più volte, non è vero? Possiamo rimuoverlo usando l'alias in questa situazione?:
Kabir Hossain il

Ti suggerisco di usare alcune tabelle temporanee;).
shA.t

5
Questo metodo sembra essere la soluzione migliore, sia per l'efficienza che per generare gli stessi risultati di a FULL OUTER JOIN. Questo post del blog lo spiega anche bene - per citare dal Metodo 2: "Questo gestisce correttamente le righe duplicate e non include nulla che non dovrebbe. È necessario utilizzare UNION ALL invece del semplice UNION, che eliminerebbe i duplicati che voglio continua. Questo potrebbe essere significativamente più efficiente su grandi set di risultati, poiché non è necessario ordinare e rimuovere i duplicati. "
Steve Chambers,

2
@SteveChambers è troppo tardi, ma grazie per il tuo commento. Ho aggiunto il tuo commento per rispondere poi a più evidenziato, se non sei d'accordo per favore, torna indietro;).
shA.t,

Nessun problema @ shA.t - IMO dovrebbe davvero avere più voti e / o essere la risposta accettata.
Steve Chambers,

6

MySql non ha sintassi FULL-OUTER-JOIN. Devi emulare facendo sia LEFT JOIN che RIGHT JOIN come segue-

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

Ma anche MySql non ha una sintassi RIGHT JOIN. Secondo la semplificazione del join esterno di MySql , il join destro viene convertito nel join sinistro equivalente commutando t1 e t2 nella clausola FROMe ONnella query. Pertanto, MySql Query Optimizer traduce la query originale nel seguente -

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

Ora, non c'è nulla di male nello scrivere la query originale così com'è, ma dite se avete predicati come la clausola WHERE, che è un predicato prima del join o un predicato AND sulla ONclausola, che è un predicato durante il join , quindi voi potrebbe voler dare un'occhiata al diavolo; che è nei dettagli.

MySql Query Optimizer controlla regolarmente i predicati se sono respinti nulli . Definizione ed esempi respinti nulli Ora, se hai eseguito RIGHT JOIN, ma con predicato WHERE sulla colonna da t1, potresti essere a rischio di imbatterti in uno scenario respinto nullo .

Ad esempio, la seguente query:

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'

viene tradotto nel seguente Strumento per ottimizzare le query:

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'

Quindi l'ordine delle tabelle è cambiato, ma il predicato è ancora applicato a t1, ma t1 è ora nella clausola 'ON'. Se t1.col1 è definito come NOT NULL colonna, questa query verrà respinta null .

Qualsiasi join esterno (sinistro, destro, pieno) che viene rifiutato null viene convertito in un join interno da MySql.

Pertanto, i risultati che potresti aspettarti potrebbero essere completamente diversi da quelli restituiti da MySql. Potresti pensare che sia un bug con RIGHT JOIN di MySql, ma non è vero. È proprio come funziona l'ottimizzatore di query MySql. Quindi lo sviluppatore responsabile deve prestare attenzione a queste sfumature quando sta costruendo la query.


4

In SQLite dovresti fare questo:

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

Possiamo usarlo? come: SELEZIONA * DA leftTable lt LEFT JOIN rightTable rt ON lt.id = rt.lrid UNION SELECT lt. *, rl. * - Per abbinare il set di colonne DA leftTable lt RIGHT JOIN rightTable rt ON lt.id = rt.lrid ;
Kabir Hossain,

sì, ma SQLite non supporta i giusti join ma sì in MYSQL sì
Rami Jamleh,

4

Nessuna delle risposte precedenti è effettivamente corretta, perché non seguono la semantica quando ci sono valori duplicati.

Per una query come (da questo duplicato ):

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

L'equivalente corretto è:

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 è necessario che funzioni con NULLvalori (che possono anche essere necessari), utilizzare l' NULLoperatore di confronto -safe <=>anziché =.


3
questa è spesso una buona soluzione, ma potrebbe dare risultati diversi rispetto a FULL OUTER JOINquando la namecolonna è nulla. La union allquery con pattern anti-join dovrebbe riprodurre correttamente il comportamento del join esterno, ma quale soluzione è più appropriata dipende dal contesto e dai vincoli attivi sulle tabelle.
fthiella,

@fthiella. . . Questo è un buon punto. Ho modificato la risposta.
Gordon Linoff,

1
ok, ma l'operatore di confronto null-safe farà sì che il join abbia successo, il che è diverso dal comportamento del join esterno completo nel caso in cui tu abbia nomi null sia in t1 che in t2
fthiella

@fthiella. . . Dovrò pensare al modo migliore per farlo. Ma dato quanto è sbagliata la risposta accettata, quasi tutto è più vicino alla risposta giusta. (Questa risposta è sbagliata se ci sono più tasti su entrambi i lati.)
Gordon Linoff

1
sì, la risposta accettata è sbagliata, come soluzione generale penso che sia corretto da usare union all, ma quella risposta manca un modello anti-join nella prima o nella seconda query che manterrà i duplicati esistenti ma impedisce di aggiungerne di nuovi. A seconda del contesto, altre soluzioni (come questa) potrebbero essere più appropriate.
fthiella,

3

Interrogazione di shA.t modificata per maggiore chiarezza:

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

3

Puoi fare quanto segue:

(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);

1

che ne dici della soluzione Cross join ?

SELECT t1.*, t2.*
FROM table1 t1
INNER JOIN table2 t2 
ON 1=1;

2
No, questo è un cross join. Abbinerà ogni riga in t1 a ogni riga in t2, producendo l'insieme di tutte le possibili combinazioni, con le select (select count(*) from t1) * (select count(*) from t2))righe nel set di risultati.
Marc L.

Mentre questo codice può rispondere alla domanda, fornendo un contesto aggiuntivo riguardo a come e perché risolve il problema migliorerebbe il valore a lungo termine della risposta.
Alexander

Quale aggiunta può essere utile? forse in esempio?
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

0

È anche possibile, ma devi selezionare gli stessi nomi di campo in 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

Questo è solo la duplicazione dei risultati da un join sinistro.
Matteo Leggi il

-1

Risolvo la risposta e le opere includono tutte le righe (basate sulla risposta di 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
    );

No, questo è un tipo di join "solo esterno", che restituirà solo le righe da tableacui non ha una corrispondenza tablebe viceversa. Si tenta di farlo UNION ALL, che funzionerebbe solo se queste due tabelle hanno colonne ordinate in modo equivalente, il che non è garantito.
Marc L.

funziona, creo sul tab temp database (1,2,3,4,5,6) e tableb (4,5,6,7,8,9) le sue righe hanno 3 colonne "id", "numero" e "name_number" come testo, e funziona in risultato hanno solo (1,2,3,7,8,9)
Rubén Ruíz,

1
Questo non è un join esterno. Un join esterno include anche i membri corrispondenti.
Marc L.,

quella nuova frase ha tutti i risultati 1,2, ..., 9
Rubén Ruíz,

-2

Risposta:

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

Può essere ricreato come segue:

 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;

L'uso di una risposta UNION o UNION ALL non copre il caso limite in cui le tabelle di base hanno voci duplicate.

Spiegazione:

C'è un caso limite che UNION o UNION ALL non possono coprire. Non possiamo testarlo su mysql poiché non supporta FULL OUTER JOINs, ma possiamo illustrarlo su un database che lo supporta:

 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 soluzione 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

Fornisce una risposta errata:

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

La soluzione 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

È anche errato.

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 che questa query:

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;

Dà quanto segue:

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

L'ordine è diverso, ma per il resto corrisponde alla risposta corretta.


È carino, ma travisa la UNION ALLsoluzione. Inoltre, presenta una soluzione UNIONche potrebbe essere più lenta su tabelle di origine di grandi dimensioni a causa della deduplicazione richiesta. Infine, non verrà compilato, poiché il campo idnon esiste nella sottoquery tmp.
Marc L.

Non ho mai fatto una richiesta sulla velocità, né l'OP ha menzionato nulla sulla velocità. Supponendo che UNION ALL (non ti affidi specifica quale) e entrambi danno la risposta corretta, se volessimo affermare che uno è più veloce, avremmo bisogno di fornire parametri di riferimento e che sarebbe divagare dal PO domanda.
Angelos,

Per quanto riguarda l'osservazione che l'id non si trova nella sottoquery, ho corretto l'errore di battitura - grazie per averlo sottolineato. La tua affermazione di false dichiarazioni è vaga - se forse potresti fornire ulteriori informazioni, posso affrontarlo. Sulla tua osservazione finale sulla carineria, non ho alcun commento, preferirei concentrarmi sulla logica del sql.
Angelos,

3
Travisa: "La UNION ALLsoluzione: ... è anche errata." Il codice che presenta esclude l'intersezione-esclusione dal join destro ( where t1.id1 is null) che deve essere fornito in UNION ALL. Vale a dire, la tua soluzione supera tutte le altre, solo quando una di quelle altre soluzioni è implementata in modo errato. Sulla "carineria", punto preso. Era gratuito, le mie scuse.
Marc L.,

-3

Lo standard SQL dice full join onè inner join onrighe union allsenza eguali righe della tabella a sinistra estese da null union allrighe della tabella a destra prorogati i null. Vale a dire inner join onfile union allnelle file left join onma non inner join on union allnelle file right join onma noninner join on .

Vale a dire left join onrighe union all right join onnon presenti inner join on. O se sai che il tuo inner join onrisultato non può avere null in una particolare colonna della tabella di destra, allora " right join onrighe non in inner join on" sono righe right join oncon la oncondizione estesa da andquella colonna is null.

Vale a dire file altrettanto right join on union allappropriate left join on.

Da Qual è la differenza tra "INNER JOIN" e "OUTER JOIN"? :

(SQL Standard 2006 SQL / Foundation 7.7 Sintassi Regole 1, Regole generali 1 b, 3 c & d, 5 b.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.