In diesem Beitrag gehe ich der Frage nach wie bekommt man mit SQL die Datensätze einer Tabelle, die nicht mit einem Datensatz einer anderen Tabelle Verknüpft sind.
Die Tabellenstruktur und Werte für die Beispiel-SQL-Abfrage sieht dabei wie folgt aus:
IDt1 |
---|
1 |
2 |
3 |
4 |
Wertt2 | IDt1 |
---|---|
101 | 1 |
102 | 2 |
103 | NULL (1) |
NULL | 4 |
Gesucht ist also der Datensatz der Tabelle tabelle1 mit dem IDt1-Wert 3.
Mittels eines JOINs können die beiden Tabellen über den Wert IDt1 mit einander verknüpft werden. Dabei sollen auch Datensätze aus tabelle1 berücksichtigt werden, die mit keinem Datensatz in tabelle2 verknüpft sind. Es wird daher ein LEFT JOIN verwendet. Die Abfrage ist dann noch auf die Datensätze zu beschränken, für die in der tabelle2 kein IDt1-Wert vorhanden ist, d.h. NULL ist.
Die SQL-Abfrage unter Verwendung eine LEFT JOIN lautet somit:
Als Ergebnis dieser Abfrage erhält man einen Datensatz, den mit dem IDt1-Wert gleich 3.
Die zweite Möglichkeit ist alle IDt1-Werte in tabelle2 in einem Subquery zu ermitteln. Im Query dann mittels NOT IN alle IDt1-Werte aus tabelle1 zu ermitteln, die nicht im Subquery vorhanden sind.
Zu beachten ist das Verhalten des IN-Operators. Dieser kann drei Werte zurückliefern: true, NULL, false
True wird ausgegeben, wenn die Unterabfrage einen Wert ungleich NULL enthält. Ist kein Wert ungleich NULL und kein NULL-Wert vorhanden, so ist der Rückgabewert false. Ist ein NULL in den Ergebnissen des Subqueries vorhanden so wird ein NULL zurückgeliefert. Mit der Negierung NOT wird true und false vertauscht, der Rückgabewert NULL bleibt aber NULL.
Da für die benötigt Query aber ein true oder false als Rückgabewert zwingend erfordert wird, muss das Vorhandensein eines NULL-Wertes im Subquery ausgeschlossen werden. Entweder muss dies von der Datentabellen-Struktur her sichergestellt sein – ist in diesem Beispiel nicht der Fall (1) – oder es muss in der SQL-Abfrage berücksichtigt werden.
Die SQL-Abfrage unter Verwendung des NOT IN lautet somit:
Als Ergebnis dieser Abfrage erhält man einen Datensatz, den mit dem IDt1-Wert gleich 3.
NOT EXISTS ist eine weitere Möglichkeit die gesuchten Datensätze zu ermitteln. In einem Subquery werden die passenden Datensätze in tabelle2 ermittelt. Der Einfachheit halber wird nur eine 1 in die Ergebnisliste aufgenommen und nicht ein Wert aus dem Datensatz, da kein spezifischer Wert benötigt wird. Da EXISTS im Unterschied zu IN nur true oder false zurückliefert muss hier keine NULL-Werte ausgeschlossen werden. Existiert im Subquery kein passender Datensatz so wird der Datensatz aus tabelle1 ausgegeben.
Die SQL-Abfrage unter Verwendung des NOT IN lautet somit:
Als Ergebnis dieser Abfrage erhält man einen Datensatz, den mit dem IDt1-Wert gleich 3.
Wenn alle drei SQL-Abfragen das gleiche Ergebnis liefern, dann stellt sich die Frage welches Query man nutzen sollte.
Um diese Frage zu beantworten habe ich beide Datentabellen mit je 50.000 Datensätzen gefüllt. Dann habe ich aller drei SQL-Abfragen ausgeführt und verglichen wie lange die einzelnen Abfragen dauerten. Zudem habe ich die Anzahl der Datensätze, die als Ergebnis zurückgeliefert werden variiert.
Die Variante mit NOT EXISTS liefert am schnellsten ein Ergebnis. Das NOT IN-Query ist etwas langsamer. Im Schnitt benötigt es 1,2-mal so lange wie die NOT EXISTS-Abfrage. Die LEFT JOIN-Variante ist die langsamste Lösung. Sie benötigt immer mehr als doppelt so lange wie die NOT EXISTS-Abfrage bis das Ergebnis der Abfrage feststeht.
Stellt man sicher, dass in der Datentabelle kein NULL-Wert vorkommt, so kann man die WHERE-Klausel bei der NOT IN-Abfrage (Zeile 7) weglassen. Dies hat zur Folge, dass die Ausführungszeit dann praktisch identisch mit der der NOT EXISTS-Abfrage ist.
Die NOT EXISTS-Variante ist die schnellste der drei Varianten.