SQL INNER JOIN: Zeilen aus zwei Tabellen verbinden

Mit SQL INNER JOIN erhältst du nur die Zeilen, bei denen die Join-Bedingung in beiden Tabellen erfüllt ist. Nutze ihn, um zusammengehörige Daten zu verknüpfen, etwa wenn du Datensätze mit Nachschlagewerten verbindest und nicht passende Zeilen im Ergebnis ausgeschlossen sein sollen. Da beide Seiten das Join-Prädikat erfüllen müssen, werden Zeilen mit einem NULL-Join-Schlüssel oder ohne passende Gegenzeile automatisch herausgefiltert.

SQL INNER JOIN Beispiel zum Verknüpfen zusammengehöriger Tabellen

Ausgabe:

Die Ausgabe erscheint hier...

Ausgabe:

+-------------+-----------+
| mitarbeiter | abteilung |
+-------------+-----------+
| Alma        | Technik   |
| Ben         | Technik   |
| Cara        | Vertrieb  |
+-------------+-----------+
3 row(s)

So funktioniert dieses Beispiel

  1. abteilungen enthält drei Abteilungen, mitarbeitende enthält vier Personen mit dem Fremdschlüssel abteilung_id. Dans abteilung_id ist NULL.
  2. INNER JOIN abteilungen a ON a.id = m.abteilung_id paart jede Mitarbeitenden-Zeile mit der Abteilungs-Zeile, deren id der abteilung_id entspricht. Es bleiben nur Paare erhalten, bei denen beide Seiten übereinstimmen.
  3. Dan hat abteilung_id = NULL. Der Operator = liefert unbekannt, wenn ein Operand NULL ist. Deshalb passt Dan zu keiner Abteilung und wird ausgeschlossen.
  4. Die Abteilung Personal (id 3) hat keine Mitarbeitenden mit passender abteilung_id, daher erscheint sie ebenfalls nicht. INNER JOIN entfernt nicht passende Zeilen auf beiden Seiten.

Was ist SQL INNER JOIN?

INNER JOIN bildet die Schnittmenge zweier Tabellen auf Basis eines Join-Prädikats. Logisch bleiben nur Zeilenpaare erhalten, bei denen die ON-Bedingung true ergibt. Die physische Ausführung hängt von Engine und Datenform ab (nested loops, hash join, merge join), das Ergebnis enthält aber immer nur passende Zeilen.

INNER JOIN vs LEFT JOIN

INNER JOINLEFT JOIN
Gibt nur passende Zeilen aus beiden Tabellen zurückGibt alle Zeilen der linken Tabelle zurück, mit NULLs, wenn rechts keine Übereinstimmung existiert
Nicht passende Zeilen werden stillschweigend entferntNicht passende linke Zeilen bleiben erhalten, rechte Spalten sind mit NULL gefüllt
Verwenden, wenn fehlende Treffer ungültige Daten bedeutenVerwenden, wenn alle linken Datensätze sichtbar bleiben sollen, auch ohne Treffer

Regel: Wähle INNER JOIN, wenn jede Ergebniszeile gültige Daten aus beiden Tabellen enthalten muss. Wechsle zu LEFT JOIN, wenn Zeilen auch ohne passenden Treffer rechts erhalten bleiben sollen.

Häufige Fehler mit SQL INNER JOIN

Fehlendes oder immer wahres Join-Prädikat

Wenn die ON-Klausel fehlt (oder eine immer wahre Bedingung verwendet wird), entsteht ein kartesisches Produkt: Jede Mitarbeitenden-Zeile wird mit jeder Abteilungs-Zeile kombiniert.

-- Falsch: kartesisches Produkt (12 Zeilen aus 4 × 3)
SELECT * FROM mitarbeitende, abteilungen;

-- Richtig: explizites Join-Prädikat
SELECT * FROM mitarbeitende m
INNER JOIN abteilungen a ON a.id = m.abteilung_id;

Nicht eindeutige Join-Schlüssel vervielfachen Zeilen

INNER JOIN liefert pro passendem Paar eine Ergebniszeile. Wenn du auf eine Tabelle mit nicht eindeutigem Schlüssel joinst, kann eine linke Zeile zu mehreren rechten Zeilen passen und dein Ergebnis vervielfachen.

INNER JOIN vs EXISTS

Verwende INNER JOIN, wenn du Spalten aus beiden Tabellen im Ergebnis brauchst. Verwende EXISTS, wenn du Zeilen nur danach filtern willst, ob eine verknüpfte Zeile vorhanden ist. EXISTS vermeidet außerdem Zeilenvervielfachung, wenn die Unterabfrage mehrere Treffer haben kann, und der Query-Planer kann oft nach dem ersten Treffer abbrechen.

-- EXISTS: eine Zeile pro Mitarbeitendem mit passender Abteilung
SELECT m.name FROM mitarbeitende m
WHERE EXISTS (SELECT 1 FROM abteilungen a WHERE a.id = m.abteilung_id);

Performance-Hinweise

Indexiere die Spalten aus dem Join-Prädikat (abteilung_id und abteilungen.id in diesem Fall). Ohne Index kann die Engine die innere Tabelle viele Male scannen. Prüfe bei großen Tabellen den Plan mit EXPLAIN QUERY PLAN und achte eher auf “USING INDEX” oder “SEARCH” als auf “SCAN”.