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?
sql
mysql
join
outer-join
full-outer-join
Spencer
quelle
quelle
Antworten:
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:
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
UNION
Set-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:quelle
(SELECT ... FROM tbl1 LEFT JOIN tbl2 ...) UNION ALL (SELECT ... FROM tbl1 RIGHT JOIN tbl2 ... WHERE tbl1.col IS NULL)
t1
und keine doppelten Zeilen vorhanden sindt2
, 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ürdeFULL OUTER JOIN
. Um eine genauere Emulation zu erhalten, benötigen wir einenUNION ALL
Set-Operator, und eine der Abfragen benötigt ein Anti-Join- Muster. Der Kommentar von Pavle Lekic (oben) gibt das richtige Abfragemuster an.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:
Innere Verbindungen
Eine innere Verbindung wie diese:
Wir würden nur Datensätze erhalten, die in beiden Tabellen wie folgt erscheinen:
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 JOIN
undRIGHT JOIN
sind Abkürzung fürLEFT OUTER JOIN
undRIGHT 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:
... 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:
Right Outer Join
Eine rechte äußere Verbindung wie folgt:
... 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:
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:
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:
Sie können sich a
UNION
als "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
UNION
in MySQL exakte Duplikate eliminiert: Tim würde in beiden Abfragen hier erscheinen, aber das Ergebnis derUNION
nur 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 wirWHERE
der zweiten Abfrage eine Klausel hinzufügen :Auf der anderen Seite, wenn Sie wollten um Duplikate sehen aus irgendeinem Grunde, könnten Sie verwenden
UNION ALL
.quelle
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 replizierenFULL OUTER JOIN
, benötigen wir eine der Abfragen, um ein Anti-Join zu sein.UNION
Operation 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 Emulierena FULL JOIN b
ist das richtige Muster(a LEFT JOIN b) UNION ALL (b ANTI JOIN a)
.Durch die Verwendung einer
union
Abfrage werden Duplikate entfernt. Dies unterscheidet sich von dem Verhalten, beifull outer join
dem niemals Duplikate entfernt werden:Dies ist das erwartete Ergebnis von
full outer join
:Dies ist das Ergebnis der Verwendung von
left
undright Join
mitunion
:[SQL Fiddle]
Meine vorgeschlagene Abfrage lautet:
Ergebnis der obigen Abfrage, das dem erwarteten Ergebnis entspricht:
[SQL Fiddle]
Ich habe beschlossen, eine weitere Lösung hinzuzufügen, die aus
full outer join
Visualisierung und Mathematik stammt. Es ist nicht besser als oben, aber besser lesbar:[SQL Fiddle]
quelle
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. "MySql hat keine FULL-OUTER-JOIN-Syntax. Sie müssen emulieren, indem Sie sowohl LEFT JOIN als auch RIGHT JOIN wie folgt ausführen:
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
FROM
undON
in der Abfrage in die entsprechende linke Verknüpfung konvertiert . Daher übersetzt das MySQL-Abfrageoptimierungsprogramm die ursprüngliche Abfrage in Folgendes: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
ON
Klausel, 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 . 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 -
wird vom Query Optimizer ins Folgende übersetzt:
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.
quelle
In SQLite sollten Sie Folgendes tun:
quelle
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 ):
Das richtige Äquivalent ist:
Wenn dies erforderlich ist, um mit
NULL
Werten zu arbeiten (was möglicherweise auch erforderlich ist), verwenden Sie denNULL
Vergleichsoperator -safe<=>
anstelle von=
.quelle
FULL OUTER JOIN
wenn diename
Spalte null ist. Dieunion all
Abfrage 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.union all
dieser 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.Die Abfrage von shA.t wurde für mehr Klarheit geändert:
quelle
Sie können Folgendes tun:
quelle
Was haben Sie über die Cross Join- Lösung gesagt ?
quelle
select (select count(*) from t1) * (select count(*) from t2))
Zeilen in der Ergebnismenge erhalten wird.quelle
Es ist auch möglich, aber Sie müssen die gleichen Feldnamen in select angeben.
quelle
Ich korrigiere die Antwort und arbeite mit allen Zeilen (basierend auf der Antwort von Pavle Lekic)
quelle
tablea
denen keine Übereinstimmung vorliegt,tableb
und umgekehrt. Das versuchen SieUNION ALL
, was nur funktionieren würde, wenn diese beiden Tabellen gleich geordnete Spalten haben, was nicht garantiert ist.Antworten:
Kann wie folgt neu erstellt werden:
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:
Die UNION-Lösung:
Gibt eine falsche Antwort:
Die UNION ALL-Lösung:
Ist auch falsch.
Während diese Abfrage:
Gibt Folgendes:
Die Reihenfolge ist unterschiedlich, entspricht aber ansonsten der richtigen Antwort.
quelle
UNION ALL
Lösung falsch dar. Außerdem wird eine Lösung vorgestellt,UNION
die bei großen Quelltabellen aufgrund der erforderlichen Deduplizierung langsamer ist. Schließlich würde es nicht kompiliert werden, da das Feldid
in der Unterabfrage nicht vorhanden isttmp
.UNION ALL
Falsche 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 mussUNION 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.Der SQL - Standard sagt
full join on
istinner join on
Reiheunion all
von Nullen unerreichte linke Tabellenzeilen erweitertenunion all
rechte Tabellenzeilen durch Nullen erweitert. Dhinner join on
Zeilenunion all
Zeilen in,left join on
aber nichtinner join on
union all
Zeilen in,right join on
aber nichtinner join on
.Dh
left join on
Reihenunion all
right join on
Reihen nicht ininner join on
. Wenn Sie wissen, dass Ihrinner join on
Ergebnis in einer bestimmten rechten Tabellenspalte nicht null enthalten kann, sind "right join on
Zeilen nicht ininner join on
" Zeilenright join on
mit deron
umand
diese Spalte erweiterten Bedingungis null
.Dh ähnlich
right join on
union all
geeigneteleft join on
Zeilen.Von Was ist der Unterschied zwischen "INNER JOIN" und "OUTER JOIN"? ::
quelle