MWCodebymw.de ↗
SQL

UNION vs. UNION ALL – zwei Abfragen zusammenlegen, ohne Zeilen zu verlieren

UNION entfernt Duplikate. Das klingt hilfreich, kostet aber eine komplette Sortierung – und wirft dir stillschweigend echte Zeilen weg, die zufällig identisch aussehen. UNION ALL ist fast immer die richtige Wahl.

Manchmal braucht man zwei Dinge in einer Liste. Eine Aktivitätsübersicht zum Beispiel: Rechnungen und Angebote, zusammen nach Datum sortiert.

SELECT 'Rechnung' AS art, nummer, erstellt_am FROM rechnungen
UNION ALL
SELECT 'Angebot'  AS art, nummer, erstellt_am FROM angebote
ORDER BY erstellt_am DESC
LIMIT 20;

Zwei Abfragen, ein Ergebnis. Zwei Regeln muss man dabei einhalten:

  • Gleiche Spaltenanzahl in beiden Teilen.
  • Passende Datentypen in derselben Reihenfolge.

Die Spaltennamen kommen aus dem ersten Teil — im zweiten kannst du sie weglassen oder anders nennen, es ändert nichts. Und ORDER BY steht ganz am Ende und gilt für das Gesamtergebnis, nicht für einen einzelnen Teil.

Der Unterschied, um den es geht

UNION ohne ALL entfernt Duplikate. Das ist keine Nebensache, sondern hat zwei Folgen:

Es kostet. Um Duplikate zu finden, muss die Datenbank das gesamte Ergebnis sortieren oder eine Hash-Tabelle aufbauen. Bei kleinen Mengen egal, bei großen deutlich spürbar.

Es kann Daten wegwerfen. Und das ist der gefährlichere Punkt:

-- ⚠️ zwei Kunden namens "Müller" aus Nürnberg → nur einer bleibt übrig
SELECT name, ort FROM kunden_alt
UNION
SELECT name, ort FROM kunden_neu;

Zwei verschiedene Kunden, die zufällig gleich heißen und am selben Ort sitzen, werden zu einer Zeile. Ohne Fehlermeldung, ohne Hinweis. Man merkt es erst, wenn eine Zahl nicht stimmt.

Meine Regel

Standard ist UNION ALL. UNION nehme ich nur, wenn ich Duplikate *bewusst* loswerden will — und dann meist mit einem eindeutigen Feld in der Auswahl, damit nicht versehentlich echte Zeilen verschwinden.

Wenn ich unsicher bin, nehme ich UNION ALL und schaue mir das Ergebnis an. Zu viele Zeilen fallen auf. Zu wenige nicht.

Zwei Details, die immer wieder auftauchen

Sortieren innerhalb eines Teils geht nicht direkt — ORDER BY gehört ans Ende. Wenn du einen Teil zuerst haben willst, hilft eine Hilfsspalte:

SELECT 1 AS gruppe, titel FROM angepinnt
UNION ALL
SELECT 2 AS gruppe, titel FROM normal
ORDER BY gruppe, titel;

LIMIT pro Teil braucht Klammern beziehungsweise eine Unterabfrage:

SELECT * FROM (SELECT titel FROM neu ORDER BY datum DESC LIMIT 5)
UNION ALL
SELECT * FROM (SELECT titel FROM beliebt ORDER BY klicks DESC LIMIT 5);

Was noch dazugehört

Neben UNION gibt es INTERSECT (nur was in beiden vorkommt) und EXCEPT (was im ersten, aber nicht im zweiten steht). Die brauche ich selten, aber wenn, dann sparen sie ein umständliches NOT EXISTS:

-- Kunden, die in der alten Liste stehen und in der neuen fehlen
SELECT email FROM kunden_alt
EXCEPT
SELECT email FROM kunden_neu;

Beide entfernen übrigens ebenfalls Duplikate — ein ALL gibt es dort in SQLite nicht.

Du hast eine Auswertung, bei der die Summe nicht zur Einzelaufstellung passt? Ein unbeabsichtigtes UNION ist ein guter erster Verdacht. Schreib mir.

Quellen

#SQL#UNION#UNION ALL#Abfragen#Performance

Du brauchst mehr als ein Snippet?

Ich entwickle Android-Apps in Kotlin und moderne Websites für Selbstständige und kleine Unternehmen — von der ersten Idee bis zum Release.

Projekt anfragen →