Wie mache ich einen FULL OUTER JOIN in MySQL?


654

Ich möchte einen vollständigen äußeren Join in MySQL durchführen. Ist das möglich? Wird ein Full Outer Join von MySQL unterstützt?



4
Diese Frage hat bessere Antworten
Julio Marins

Hüten Sie sich vor den Antworten hier. Der SQL-Standard besagt, dass die vollständige Verknüpfung die innere Verknüpfung der Zeilen ist. Alle nicht übereinstimmenden linken Tabellenzeilen werden um Nullen erweitert. Alle rechten Tabellenzeilen werden um Nullen erweitert. Die meisten Antworten hier sind falsch (siehe Kommentare) und diejenigen, die nicht falsch sind, behandeln den allgemeinen Fall nicht. Obwohl es viele (ungerechtfertigte) Gegenstimmen gibt. (Siehe meine Antwort.)
philipxy

Was ist, wenn Sie versuchen, über Nicht-Primärschlüssel / gruppierte Spalten beizutreten? Wie ich eine Abfrage von Verkäufen pro Staat "Staat", "Verkauf" und eine andere von Ausgaben pro Staat "Staat", "Ausgaben" habe, verwenden beide Abfragen die Gruppierung nach ("Staat"). Wenn ich die Verbindung zwischen links und rechts zu zwei Abfragen herstelle, erhalte ich ein paar Zeilen mit Verkäufen, aber ohne Kosten, ein paar mehr mit Kosten, aber ohne Verkäufe, alles bis zu diesem Punkt, aber ich bekomme auch ein paar mit beiden Verkäufe und Ausgaben und eine wiederholte "Zustand" -Spalte ... kein großes Problem, fühlt sich aber nicht richtig an ...
Jairo Lozano

1
@JairoLozano Einschränkungen sind für die Abfrage nicht erforderlich. Wenn Einschränkungen zusätzliche Abfragen enthalten, wird die gewünschte Antwort zurückgegeben, die sonst nicht gegeben wäre. Einschränkungen haben keinen Einfluss darauf, welche vollständige Verknüpfung bei Rückgaben für bestimmte Argumente erfolgt. Das von Ihnen beschriebene Problem besteht darin, dass die von Ihnen geschriebene Abfrage die falsche Abfrage ist. (Vermutlich der häufigste Fehler, bei dem Benutzer einige Verknüpfungen, von denen jede möglicherweise einen anderen Schlüssel enthält, für einige Unterabfragen wünschen, von denen jede möglicherweise Verknüpfungen und / oder Aggregationen enthält, aber sie versuchen fälschlicherweise, alle Verknüpfungen und dann alle Aggregationen durchzuführen oder über vorherige Aggregationen zu aggregieren .)
philipxy

Antworten:


668

Sie haben keine FULL JOINS unter MySQL, aber Sie können sie sicher emulieren .

Für einen Code SAMPLE, der von dieser SO-Frage transkribiert wurde , haben Sie:

mit zwei Tabellen 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

Die obige Abfrage funktioniert in besonderen Fällen, in denen eine FULL OUTER JOIN-Operation keine doppelten Zeilen erzeugen würde. Die obige Abfrage hängt vom UNIONSet-Operator ab, um doppelte Zeilen zu entfernen, die durch das Abfragemuster eingeführt wurden. Wir können die Einführung doppelter Zeilen vermeiden, indem wir für die zweite Abfrage ein Anti-Join- Muster verwenden und dann einen UNION ALL-Mengenoperator verwenden, um die beiden Mengen zu kombinieren. Im allgemeineren Fall, in dem ein FULL OUTER JOIN doppelte Zeilen zurückgeben würde, können wir dies tun:

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
Eigentlich ist das, was Sie geschrieben haben, nicht korrekt. Denn wenn Sie eine UNION ausführen, werden Sie Duplikate entfernen, und manchmal, wenn Sie zwei verschiedene Tabellen verbinden, sollten Duplikate vorhanden sein.
Pavle Lekic

158
Dies ist das richtige Beispiel:(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
Pavle Lekic

8
Der Unterschied ist also, dass ich mit UNION ALL
Pavle Lekic am

5
und ich sehe jetzt, dass du das selbst sagst, sorry. Vielleicht könnten Sie Ihre Antwort aktualisieren, wenn in diesem Fall etwas falsch läuft und die UNION ALL immer effizienter wird?
Ysth

10
@ypercube: Wenn in t1und keine doppelten Zeilen vorhanden sind t2, gibt die Abfrage in dieser Antwort eine Ergebnismenge zurück, die FULL OUTER JOIN emuliert. Im allgemeineren Fall enthält die SELECT-Liste jedoch nicht genügend Spalten / Ausdrücke, um die zurückgegebenen Zeilen eindeutig zu machen. Dann reicht dieses Abfragemuster nicht aus , um die Menge zu reproduzieren, die von a erzeugt würde FULL OUTER JOIN. Um eine genauere Emulation zu erhalten, benötigen wir einen UNION ALLSet-Operator, und eine der Abfragen benötigt ein Anti-Join- Muster. Der Kommentar von Pavle Lekic (oben) gibt das richtige Abfragemuster an.
Spencer7593

350

Die Antwort, die Pablo Santa Cruz gab, ist richtig; Falls jedoch jemand auf diese Seite gestoßen ist und weitere Erläuterungen wünscht, finden Sie hier eine detaillierte Aufschlüsselung.

Beispieltabellen

Angenommen, wir haben die folgenden Tabellen:

-- t1
id  name
1   Tim
2   Marta

-- t2
id  name
1   Tim
3   Katarina

Innere Verbindungen

Eine innere Verbindung wie diese:

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

Wir würden nur Datensätze erhalten, die in beiden Tabellen wie folgt erscheinen:

1 Tim  1 Tim

Innere Verknüpfungen haben keine Richtung (wie links oder rechts), da sie explizit bidirektional sind - wir benötigen eine Übereinstimmung auf beiden Seiten.

Äußere Verbindungen

Äußere Verknüpfungen dienen andererseits zum Auffinden von Datensätzen, die möglicherweise nicht mit der anderen Tabelle übereinstimmen. Daher müssen Sie angeben, auf welcher Seite des Joins ein Datensatz fehlen darf.

LEFT JOINund RIGHT JOINsind Abkürzung für LEFT OUTER JOINund RIGHT OUTER JOIN; Ich werde ihre vollständigen Namen unten verwenden, um das Konzept der äußeren Verknüpfungen gegenüber den inneren Verknüpfungen zu verstärken.

Linke äußere Verbindung

Eine linke äußere Verbindung wie folgt:

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

... würde uns alle Datensätze aus der linken Tabelle holen, unabhängig davon, ob sie eine Übereinstimmung in der rechten Tabelle haben oder nicht, wie folgt:

1 Tim   1    Tim
2 Marta NULL NULL

Right Outer Join

Eine rechte äußere Verbindung wie folgt:

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

... würde uns alle Datensätze aus der rechten Tabelle holen, unabhängig davon, ob sie eine Übereinstimmung in der linken Tabelle haben oder nicht, wie folgt:

1    Tim   1  Tim
NULL NULL  3  Katarina

Volle äußere Verbindung

Eine vollständige äußere Verknüpfung würde uns alle Datensätze aus beiden Tabellen geben, unabhängig davon, ob sie in der anderen Tabelle übereinstimmen oder nicht, mit NULL-Werten auf beiden Seiten, auf denen keine Übereinstimmung vorliegt. Das Ergebnis würde folgendermaßen aussehen:

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

Wie Pablo Santa Cruz jedoch betonte, unterstützt MySQL dies nicht. Wir können es emulieren, indem wir eine UNION aus einem linken und einem rechten Join wie folgt durchführen:

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

Sie können sich a UNIONals "beide Abfragen ausführen und dann die Ergebnisse übereinander stapeln" vorstellen. Einige der Zeilen stammen aus der ersten Abfrage, andere aus der zweiten.

Es sollte beachtet werden, dass a UNIONin MySQL exakte Duplikate eliminiert: Tim würde in beiden Abfragen hier erscheinen, aber das Ergebnis der UNIONnur listet ihn einmal auf. Mein Datenbank-Guru-Kollege ist der Meinung, dass man sich nicht auf dieses Verhalten verlassen sollte. Um dies genauer zu beschreiben, könnten wir WHEREder zweiten Abfrage eine Klausel hinzufügen :

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;

Auf der anderen Seite, wenn Sie wollten um Duplikate sehen aus irgendeinem Grunde, könnten Sie verwenden UNION ALL.


12
Diese Antwort ist mehr als ein Jahr alt, aber es stellt sich heraus, dass Herr Atwood 2007 eine noch bessere Antwort auf seinem Blog hatte: codinghorror.com/blog/2007/10/…
Nathan Long

4
Für MySQL möchten Sie wirklich vermeiden, UNION anstelle von UNION ALL zu verwenden, wenn es keine Überlappung gibt (siehe Kommentar von Pavle oben). Wenn Sie in Ihrer Antwort hier weitere Informationen zu diesem Effekt hinzufügen könnten, wäre dies meiner Meinung nach die bevorzugte Antwort auf diese Frage, da sie gründlicher ist.
Garen

2
Die Empfehlung des "Datenbank-Guru-Kollegen" ist richtig. In Bezug auf das relationale Modell (alle theoretischen Arbeiten von Ted Codd und Chris Date) emuliert eine Abfrage der letzten Form einen FULL OUTER JOIN, da sie zwei unterschiedliche Mengen kombiniert. Die zweite Abfrage führt keine "Duplikate" ein ( Zeilen, die bereits von der ersten Abfrage zurückgegeben wurden), die von a nicht erzeugt würden FULL OUTER JOIN. Es ist nichts Falsches daran, Abfragen auf diese Weise durchzuführen und UNION zum Entfernen dieser Duplikate zu verwenden. Aber um a wirklich zu replizieren FULL OUTER JOIN, benötigen wir eine der Abfragen, um ein Anti-Join zu sein.
Spencer7593

1
@IstiaqueAhmed: Das Ziel ist es, eine FULL OUTER JOIN-Operation zu emulieren. Wir benötigen diese Bedingung in der zweiten Abfrage, damit nur Zeilen zurückgegeben werden, die nicht übereinstimmen (ein Anti-Join-Muster). Ohne diese Bedingung ist die Abfrage eine äußere Verknüpfung. Sie gibt Zeilen zurück, die übereinstimmen, sowie Zeilen ohne Übereinstimmung. Und die übereinstimmenden Zeilen wurden bereits von der ersten Abfrage zurückgegeben. Wenn die zweite Abfrage (erneut) dieselben Zeilen zurückgibt, haben wir Zeilen dupliziert und unser Ergebnis entspricht nicht einem FULL OUTER JOIN.
Spencer7593

1
@IstiaqueAhmed: Es ist wahr, dass eine UNIONOperation diese Duplikate entfernt; Es werden jedoch auch ALLE doppelten Zeilen entfernt, einschließlich doppelter Zeilen, die von einem FULL OUTER JOIN zurückgegeben werden. Zum Emulieren a FULL JOIN bist das richtige Muster (a LEFT JOIN b) UNION ALL (b ANTI JOIN a).
Spencer7593

35

Durch die Verwendung einer unionAbfrage werden Duplikate entfernt. Dies unterscheidet sich von dem Verhalten, bei full outer joindem niemals Duplikate entfernt werden:

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

Dies ist das erwartete Ergebnis von full outer join:

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

Dies ist das Ergebnis der Verwendung von leftund right Joinmit union:

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

[SQL Fiddle]

Meine vorgeschlagene Abfrage lautet:

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 

Ergebnis der obigen Abfrage, das dem erwarteten Ergebnis entspricht:

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

[SQL Fiddle]


@Steve Chambers : [Aus Kommentaren, vielen Dank!]
Hinweis: Dies ist möglicherweise die beste Lösung, sowohl für die Effizienz als auch für die Generierung der gleichen Ergebnisse wie a FULL OUTER JOIN. Dieser Blog-Beitrag erklärt es auch gut - um aus Methode 2 zu zitieren: "Dies behandelt doppelte Zeilen korrekt und enthält nichts, was es nicht sollte. Es ist notwendig, UNION ALLanstelle von einfach zu verwenden UNION, wodurch die Duplikate beseitigt würden, die ich behalten möchte kann bei großen Ergebnismengen erheblich effizienter sein, da keine Duplikate sortiert und entfernt werden müssen. "


Ich habe beschlossen, eine weitere Lösung hinzuzufügen, die aus full outer joinVisualisierung und Mathematik stammt. Es ist nicht besser als oben, aber besser lesbar:

Vollständige äußere Verknüpfung bedeutet (t1 ∪ t2): all in t1oder in t2
(t1 ∪ t2) = (t1 ∩ t2) + t1_only + t2_only: all in beiden t1und t2plus all in t1, die nicht in t2und plus all in t2, die nicht 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]


Wir erledigen die gleichen Aufgaben zwei Mal. Wenn es Unterabfragen für t1 und t2 gibt, muss MySQL die gleiche Aufgabe mehrmals ausführen, nicht wahr? Können wir dies in dieser Situation mit einem Alias ​​entfernen ?:
Kabir Hossain

Ich schlage vor, einige temporäre Tabellen zu verwenden;).
shA.t

5
Diese Methode scheint die beste Lösung zu sein, sowohl für die Effizienz als auch für die Erzielung der gleichen Ergebnisse wie a FULL OUTER JOIN. Dieser Blog-Beitrag erklärt es auch gut - um aus Methode 2 zu zitieren: "Dies behandelt doppelte Zeilen korrekt und enthält nichts, was es nicht sollte. Es ist notwendig, UNION ALL anstelle von einfachem UNION zu verwenden, wodurch die von mir gewünschten Duplikate entfernt würden Dies kann bei großen Ergebnismengen erheblich effizienter sein, da keine Duplikate sortiert und entfernt werden müssen. "
Steve Chambers

2
@SteveChambers es ist zu spät, aber danke für deinen Kommentar. Ich habe Ihren Kommentar hinzugefügt, um dann auf die hervorgehobenen Punkte zu antworten. Wenn Sie nicht einverstanden sind, rollen Sie ihn bitte zurück;).
shA.t

Kein Problem @ shA.t - IMO sollte dies wirklich mehr Upvotes haben und / oder die akzeptierte Antwort sein.
Steve Chambers

6

MySql hat keine FULL-OUTER-JOIN-Syntax. Sie müssen emulieren, indem Sie sowohl LEFT JOIN als auch RIGHT JOIN wie folgt ausführen:

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

MySql verfügt jedoch auch nicht über eine RIGHT JOIN-Syntax. Gemäß der Vereinfachung der äußeren Verknüpfung von MySql wird die rechte Verknüpfung durch Umschalten von t1 und t2 in der Klausel FROMund ONin der Abfrage in die entsprechende linke Verknüpfung konvertiert . Daher übersetzt das MySQL-Abfrageoptimierungsprogramm die ursprüngliche Abfrage in Folgendes:

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

Jetzt kann es nicht schaden, die ursprüngliche Abfrage so zu schreiben, wie sie ist. Wenn Sie jedoch Prädikate wie die WHERE-Klausel haben, bei der es sich um ein Prädikat vor dem Join handelt, oder ein UND-Prädikat für die ONKlausel, bei der es sich um ein Prädikat beim Join handelt , dann sind Sie es Vielleicht möchten Sie einen Blick auf den Teufel werfen. Das ist im Detail.

Das MySQL-Abfrageoptimierungsprogramm überprüft die Prädikate routinemäßig, wenn sie nicht zurückgewiesen werden . Null-abgelehnte Definition und Beispiele Wenn Sie nun den RIGHT JOIN ausgeführt haben, aber mit dem WHERE-Prädikat für die Spalte von t1, besteht möglicherweise das Risiko, dass Sie auf ein Szenario mit Null-Zurückweisung stoßen.

Zum Beispiel die folgende Abfrage -

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'

wird vom Query Optimizer ins Folgende übersetzt:

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'

Die Reihenfolge der Tabellen hat sich also geändert, aber das Prädikat wird immer noch auf t1 angewendet, aber t1 befindet sich jetzt in der 'ON'-Klausel. Wenn t1.col1 als NOT NULL Spalte definiert ist , wird diese Abfrage null zurückgewiesen .

Jeder äußere Join (links, rechts, voll), der null abgelehnt wird, wird von MySql in einen inneren Join konvertiert.

Daher können die erwarteten Ergebnisse völlig anders ausfallen als die von MySql zurückgegebenen. Sie könnten denken, es ist ein Fehler mit MySqls RIGHT JOIN, aber das ist nicht richtig. So funktioniert der MySql-Abfrageoptimierer. Daher muss der verantwortliche Entwickler diese Nuancen bei der Erstellung der Abfrage berücksichtigen.


4

In SQLite sollten Sie Folgendes tun:

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

Können wir es benutzen? wie folgt: SELECT * FROM leftTable lt LEFT JOIN rightTable rt ON lt.id = rt.lrid UNION SELECT lt. *, rl. * - Zum Abgleichen des Spaltensatzes FROM leftTable lt RIGHT JOIN rightTable rt ON lt.id = rt.lrid ;;
Kabir Hossain

Ja, aber SQLite unterstützt keine richtigen Joins, aber Ja in MYSQL. Ja
Rami Jamleh,

4

Keine der obigen Antworten ist tatsächlich richtig, da sie bei doppelten Werten nicht der Semantik folgen.

Für eine Abfrage wie (aus diesem Duplikat ):

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

Das richtige Äquivalent ist:

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;

Wenn dies erforderlich ist, um mit NULLWerten zu arbeiten (was möglicherweise auch erforderlich ist), verwenden Sie den NULLVergleichsoperator -safe <=>anstelle von =.


3
Dies ist oft eine gute Lösung, kann jedoch zu anderen Ergebnissen führen als a, FULL OUTER JOINwenn die nameSpalte null ist. Die union allAbfrage mit Anti-Join-Muster sollte das äußere Join-Verhalten korrekt wiedergeben. Welche Lösung jedoch besser geeignet ist, hängt vom Kontext und den Einschränkungen ab, die für die Tabellen aktiv sind.
Fthiella

@fthiella. . . Das ist ein guter Punkt. Ich habe die Antwort angepasst.
Gordon Linoff

1
Okay, aber der null-sichere Vergleichsoperator führt dazu, dass der Join erfolgreich ist.
Dies

@fthiella. . . Ich muss mir überlegen, wie ich das am besten machen kann. Aber wenn man bedenkt, wie falsch die akzeptierte Antwort ist, ist fast alles näher an der richtigen Antwort. (Diese Antwort ist einfach falsch, wenn auf beiden Seiten mehrere Schlüssel vorhanden sind.)
Gordon Linoff

1
Ja, die akzeptierte Antwort ist falsch. Als allgemeine Lösung halte ich sie für richtig. Bei union alldieser Antwort fehlt jedoch ein Anti-Join-Muster in der ersten oder zweiten Abfrage, das vorhandene Duplikate beibehält, aber das Hinzufügen neuer verhindert. Je nach Kontext sind andere Lösungen (wie diese) möglicherweise besser geeignet.
Fthiella

3

Die Abfrage von shA.t wurde für mehr Klarheit geändert:

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

Sie können Folgendes tun:

(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

Was haben Sie über die Cross Join- Lösung gesagt ?

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

2
Nein, dies ist ein Cross Join. Es wird jede Zeile in t1 mit jeder Zeile in t2 abgeglichen, wodurch die Menge aller möglichen Kombinationen mit select (select count(*) from t1) * (select count(*) from t2))Zeilen in der Ergebnismenge erhalten wird.
Marc L.

Während dieser Code die Frage möglicherweise beantwortet, würde die Bereitstellung eines zusätzlichen Kontexts darüber, wie und warum das Problem gelöst wird, den langfristigen Wert der Antwort verbessern.
Alexander

Welcher Zusatz kann hilfreich sein? vielleicht en beispiel?
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

Es ist auch möglich, aber Sie müssen die gleichen Feldnamen in select angeben.

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

Dies dupliziert nur die Ergebnisse eines linken Joins.
Matthew Read

-1

Ich korrigiere die Antwort und arbeite mit allen Zeilen (basierend auf der Antwort von 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
    );

Nein, dies ist eine Art "Nur-Außen" -Verbindung, die nur die Zeilen zurückgibt, von tableadenen keine Übereinstimmung vorliegt, tablebund umgekehrt. Das versuchen Sie UNION ALL, was nur funktionieren würde, wenn diese beiden Tabellen gleich geordnete Spalten haben, was nicht garantiert ist.
Marc L.

es funktioniert, ich erstelle auf temporären Datenbank tablea (1,2,3,4,5,6) und tableb (4,5,6,7,8,9) seine Zeilen haben 3 Spalten "id", "number" und "name_number" als Text und funktioniert im Ergebnis nur haben (1,2,3,7,8,9)
Rubén Ruíz

1
Das ist keine äußere Verbindung. Eine äußere Verknüpfung enthält auch die übereinstimmenden Mitglieder.
Marc L.

Dieser neue Satz hat alle Ergebnisse 1,2, ..., 9
Rubén Ruíz

-2

Antworten:

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

Kann wie folgt neu erstellt werden:

 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;

Die Verwendung einer UNION- oder UNION ALL-Antwort deckt nicht den Randfall ab, in dem die Basistabellen doppelte Einträge haben.

Erläuterung:

Es gibt einen Randfall, den eine UNION oder UNION ALL nicht abdecken kann. Wir können dies nicht auf MySQL testen, da es keine FULL OUTER JOINs unterstützt, aber wir können dies in einer Datenbank veranschaulichen, die es unterstützt:

 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

Die UNION-Lösung:

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

Gibt eine falsche Antwort:

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

Die UNION ALL-Lösung:

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

Ist auch falsch.

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

Während diese Abfrage:

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;

Gibt Folgendes:

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

Die Reihenfolge ist unterschiedlich, entspricht aber ansonsten der richtigen Antwort.


Das ist süß, stellt aber die UNION ALLLösung falsch dar. Außerdem wird eine Lösung vorgestellt, UNIONdie bei großen Quelltabellen aufgrund der erforderlichen Deduplizierung langsamer ist. Schließlich würde es nicht kompiliert werden, da das Feld idin der Unterabfrage nicht vorhanden ist tmp.
Marc L.

Ich habe nie einen Anspruch auf Geschwindigkeit erhoben, und das OP hat auch nichts über Geschwindigkeit erwähnt. Angenommen, die UNION ALL (Sie verlassen sich nicht darauf, welche anzugeben) und beide geben die richtige Antwort. Wenn wir die Behauptung aufstellen möchten, dass eine schneller ist, müssten wir Benchmarks bereitstellen, und das würde vom OP abweichen Frage.
Angelos

In Bezug auf die Beobachtung, dass die ID nicht in der Unterabfrage enthalten ist, habe ich den Tippfehler korrigiert - danke, dass Sie darauf hingewiesen haben. Ihre Behauptung über falsche Darstellungen ist vage - wenn Sie vielleicht mehr Informationen liefern könnten, kann ich das ansprechen. Zu Ihrer letzten Bemerkung zur Niedlichkeit habe ich keinen Kommentar, ich möchte mich lieber auf die Logik des SQL konzentrieren.
Angelos

3
UNION ALLFalsche Darstellung: "Die Lösung: ... ist auch falsch." Der von Ihnen präsentierte Code lässt den Schnittpunktausschluss von right-join ( where t1.id1 is null) aus, der in der Datei angegeben werden muss UNION ALL. Das heißt, Ihre Lösung übertrifft alle anderen nur dann, wenn eine dieser anderen Lösungen falsch implementiert ist. Auf "Niedlichkeit" Punkt genommen. Das war unentgeltlich, ich entschuldige mich.
Marc L.

-3

Der SQL - Standard sagt full join onist inner join onReihe union allvon Nullen unerreichte linke Tabellenzeilen erweiterten union allrechte Tabellenzeilen durch Nullen erweitert. Dh inner join onZeilen union allZeilen in, left join onaber nicht inner join on union allZeilen in, right join onaber nicht inner join on.

Dh left join onReihen union all right join onReihen nicht in inner join on. Wenn Sie wissen, dass Ihr inner join onErgebnis in einer bestimmten rechten Tabellenspalte nicht null enthalten kann, sind " right join onZeilen nicht in inner join on" Zeilen right join onmit der onum anddiese Spalte erweiterten Bedingung is null.

Dh ähnlich right join on union allgeeignete left join onZeilen.

Von Was ist der Unterschied zwischen "INNER JOIN" und "OUTER JOIN"? ::

(SQL Standard 2006 SQL / Foundation 7.7 Syntaxregeln 1, Allgemeine Regeln 1 b, 3 c & d, 5 b.)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.