Duplikate in SQL zu entfernen bedeutet eines von zwei Dingen: wiederholte Zeilen mit DISTINCT im Ergebnis einer Abfrage auszublenden oder die überzähligen Kopien aus der Tabelle zu löschen, sodass von jeder nur eine übrig bleibt. Die Beispiele funktionieren in PostgreSQL, MySQL, SQLite und SQL Server.
So entfernst du Duplikate in SQL
SELECT DISTINCT gibt jede Kombination der angegebenen Spalten einmal zurück und lässt die Tabelle unverändert. Um die Tabelle selbst zu bereinigen, löschst du in jeder Gruppe von Duplikaten alle Zeilen bis auf eine, meist die mit der niedrigsten ID:
SELECT DISTINCT column_list FROM table_name;
DELETE FROM table_name
WHERE id NOT IN (
SELECT id FROM (
SELECT MIN(id) AS id FROM table_name GROUP BY column_list
) AS keepers
);
Hier wurde Maria Lopez dreimal eingetragen:
-- Input: customers
-- id | name | email | phone
-- ---+-------------+-------------------+---------
-- 1 | Maria Lopez | maria@example.com | 555-0142
-- 2 | Sam Patel | sam@example.com | 555-0178
-- 3 | Maria Lopez | maria@example.com | 555-0142
-- 4 | Lena Novak | lena@example.com | 555-0121
-- 5 | Maria Lopez | maria@example.com | 555-0142
SELECT DISTINCT name, email, phone
FROM customers
ORDER BY name;
-- Output:
-- name | email | phone
-- ------------+-------------------+---------
-- Lena Novak | lena@example.com | 555-0121
-- Maria Lopez | maria@example.com | 555-0142
-- Sam Patel | sam@example.com | 555-0178
DELETE FROM customers
WHERE id NOT IN (
SELECT id FROM (
SELECT MIN(id) AS id FROM customers GROUP BY name, email, phone
) AS keepers
);
-- Output (customers after the DELETE):
-- id | name | email | phone
-- ---+-------------+-------------------+---------
-- 1 | Maria Lopez | maria@example.com | 555-0142
-- 2 | Sam Patel | sam@example.com | 555-0178
-- 4 | Lena Novak | lena@example.com | 555-0121
Wichtige Regeln
-
Gib die Spalten an, die zwei Zeilen zu Duplikaten machen. Lass die ID weg und alles andere, was sich immer unterscheidet, etwa einen
created_at-Zeitstempel. Zeilen, die sich in irgendeiner angegebenen Spalte unterscheiden, bleiben alle erhalten. -
Die Hülle
SELECT id FROM (...) AS keepersist für MySQL gedacht, das einemDELETEsonst verbietet, seine eigene Tabelle in einer Unterabfrage zu lesen: „You can’t specify target table ‘customers’ for update in FROM clause“. -
Erst schauen, dann löschen. Führe zuerst die
GROUP BY- oderROW_NUMBER()-Abfrage aus, um zu sehen, was wegfällt, und lösche innerhalb einer Transaktion, die du zurückrollen kannst. - Verhindere neue Duplikate mit einem Unique-Index, sobald die Tabelle sauber ist:
CREATE UNIQUE INDEX customers_email_key ON customers (email);
INSERT INTO customers VALUES (6, 'Maria Lopez', 'maria@example.com', '555-0142');
-- ERROR: duplicate key value violates unique constraint "customers_email_key"
Alternative Syntax
In SQL-Server-Code siehst du oft, dass die Kopien in einer CTE nummeriert und über sie gelöscht werden – das erlaubt nur SQL Server. Mit der ursprünglichen customers-Tabelle:
-- SQL Server
WITH numbered AS (
SELECT *, ROW_NUMBER() OVER (
PARTITION BY name, email, phone ORDER BY id
) AS row_num
FROM customers
)
DELETE FROM numbered WHERE row_num > 1;
-- Output (customers after the DELETE):
-- id | name | email | phone
-- ---+-------------+-------------------+---------
-- 1 | Maria Lopez | maria@example.com | 555-0142
-- 2 | Sam Patel | sam@example.com | 555-0178
-- 4 | Lena Novak | lena@example.com | 555-0121
Um zwei Abfragen ohne doppelte Zeilen zu kombinieren, nutze UNION, das Duplikate entfernt, statt UNION ALL, das sie behält:
SELECT 'apple' AS fruit UNION ALL SELECT 'apple';
-- Output:
-- fruit
-- -----
-- apple
-- apple
SELECT 'apple' AS fruit UNION SELECT 'apple';
-- Output: apple
Wann solltest du Duplikate entfernen?
Manchmal musst du Wiederholungen nur im Ergebnis ausblenden, manchmal muss die Tabelle selbst bereinigt werden. Das sind die üblichen Schritte, vom Anschauen bis zum Löschen.
Jeden Wert einmal anzeigen
Für einen Bericht, ein Dropdown oder einen schnellen Blick darauf, was in einer Spalte steht, entfernt SELECT DISTINCT die Wiederholungen aus dem Ergebnis und lässt die Tabelle, wie sie ist.
Kopien vor dem Löschen zählen
Gruppiere nach den Spalten, die ein Duplikat definieren, und behalte die Gruppen mit HAVING COUNT(*) > 1. So siehst du, was doppelt ist und wie oft, bevor etwas entfernt wird. Der Leitfaden zum Finden von Duplikaten in SQL zeigt weitere Möglichkeiten.
Wähle, welche Kopie bleibt
ROW_NUMBER() nummeriert die Zeilen in jeder Gruppe von Duplikaten. Das ORDER BY innerhalb von OVER (...) entscheidet, welche Zeile die 1 bekommt und bleibt: die älteste, die neueste oder die vollständigste.
Überzählige Kopien löschen
Sobald du weißt, welche Zeile bleiben soll, löschst du die anderen. Um die neueste statt der ältesten Zeile zu behalten, nummerierst du die Zeilen nach Datum, neueste zuerst, und löschst alles mit einer Nummer über 1.
Praxisbeispiele zum Entfernen von Duplikaten
Alle Länder und Versanddienstleister, mit denen du versendest
DISTINCT gilt für die gesamte Zeile der ausgewählten Spalten, daher erscheint Kanada einmal pro Versanddienstleister:
-- Input: shipments
-- order_id | country | carrier
-- ---------+---------+--------
-- 1001 | Canada | UPS
-- 1002 | Germany | DHL
-- 1003 | Canada | FedEx
-- 1004 | Canada | UPS
-- 1005 | Germany | DHL
SELECT DISTINCT country, carrier
FROM shipments
ORDER BY country, carrier;
-- Output:
-- country | carrier
-- --------+--------
-- Canada | FedEx
-- Canada | UPS
-- Germany | DHL
E-Mail-Adressen, die sich nur in der Groß-/Kleinschreibung unterscheiden
Gruppiere nach der kleingeschriebenen E-Mail, damit Jon@Example.com und jon@example.com als Kopien zählen. (MySQL und SQL Server ignorieren Groß-/Kleinschreibung standardmäßig ohnehin, und LOWER() schadet dort nicht.)
-- Input: accounts
-- id | email
-- ---+----------------------
-- 1 | Ana.Silva@example.com
-- 2 | jon@example.com
-- 3 | ana.silva@example.com
-- 4 | Jon@Example.com
-- 5 | mei@example.com
SELECT LOWER(email) AS email, COUNT(*) AS copies
FROM accounts
GROUP BY LOWER(email)
HAVING COUNT(*) > 1
ORDER BY email;
-- Output:
-- email | copies
-- ----------------------+-------
-- ana.silva@example.com | 2
-- jon@example.com | 2
Die Kopie mit Telefonnummer behalten
Sortiere die Zeilen mit Telefonnummer zuerst, dann nach ID, sodass die vollständigste Zeile jeder Gruppe die Nummer 1 ist:
-- Input: contacts
-- id | email | phone
-- ---+------------------+---------
-- 1 | ravi@example.com | NULL
-- 2 | ravi@example.com | 555-0110
-- 3 | ines@example.com | 555-0133
-- 4 | ines@example.com | NULL
SELECT
id,
email,
phone,
ROW_NUMBER() OVER (
PARTITION BY email
ORDER BY CASE WHEN phone IS NULL THEN 1 ELSE 0 END, id
) AS row_num
FROM contacts
ORDER BY email, row_num;
-- Output:
-- id | email | phone | row_num
-- ---+------------------+----------+--------
-- 3 | ines@example.com | 555-0133 | 1
-- 4 | ines@example.com | NULL | 2
-- 2 | ravi@example.com | 555-0110 | 1
-- 1 | ravi@example.com | NULL | 2
Wenn du die Zeilen mit Nummer 2 oder höher (IDs 1 und 4) löschst, bleibt pro E-Mail ein vollständiger Kontakt übrig.
Exakte Kopien aus einer Tabelle ohne ID löschen
Wenn die Kopien in jeder Spalte identisch sind, gibt es keine ID, deren niedrigste du behalten könntest. Kopiere die eindeutigen Zeilen in eine neue Tabelle und tausche sie aus. Füge alle Indizes und Constraints der alten Tabelle wieder hinzu, denn die Kopie übernimmt sie nicht:
-- Input: page_views
-- url | viewed_at
-- ---------+--------------------
-- /pricing | 2026-10-01 09:00:00
-- /pricing | 2026-10-01 09:00:00
-- /docs | 2026-10-01 09:05:00
-- /pricing | 2026-10-01 09:00:00
-- In SQL Server, use SELECT DISTINCT * INTO page_views_clean FROM page_views,
-- then EXEC sp_rename 'page_views_clean', 'page_views'
CREATE TABLE page_views_clean AS SELECT DISTINCT * FROM page_views;
DROP TABLE page_views;
ALTER TABLE page_views_clean RENAME TO page_views;
-- Output (page_views afterwards):
-- url | viewed_at
-- ---------+--------------------
-- /pricing | 2026-10-01 09:00:00
-- /docs | 2026-10-01 09:05:00
Weiterführende Artikel zum Entfernen von Duplikaten
In diesem Blog:
- Leitfaden zum Finden von Duplikaten in SQL: weitere Wege, doppelte Zeilen vor dem Entfernen aufzuspüren
- Doppelte Zeilen in einer SQL-Server-Tabelle erkennen: die SQL-Server-Perspektive
- Leitfaden zu SQL COUNT DISTINCT: eindeutige Werte zählen statt Wiederholungen entfernen
- SQL-DELETE-Anweisung: Syntax und Beispiele: die Grundlagen zum Löschen von Zeilen
- Unique Constraints in PostgreSQL erstellen: Duplikate dauerhaft fernhalten
- SQL CTE vs. Unterabfrage: die zwei Arten, den Schritt „welche Zeilen bleiben“ zu schreiben
Offizielle Dokumentation:
- PostgreSQL: DELETE und Fensterfunktionen
- MySQL: DELETE und ROW_NUMBER()
- SQLite: DELETE und Fensterfunktionen
- SQL Server: DELETE und ROW_NUMBER
Beekeeper Studio ist eine kostenlose & quelloffene Datenbank-GUI
Das beste SQL-Abfrage- & Editor-Tool, das ich je benutzt habe. Es bietet alles, was ich zum Verwalten meiner Datenbank brauche. - ⭐⭐⭐⭐⭐ Mit
Beekeeper Studio ist schnell, intuitiv und einfach zu bedienen. Beekeeper unterstützt jede Menge Datenbanken und läuft hervorragend auf Windows, Mac und Linux.
Was Nutzer über Beekeeper Studio sagen
„Beekeeper Studio hat meinen alten SQL-Workflow komplett ersetzt. Es ist schnell, intuitiv und macht die Arbeit mit Datenbanken wieder zum Vergnügen.“
„Ich habe viele Datenbank-GUIs ausprobiert, aber Beekeeper trifft die perfekte Balance zwischen Funktionsumfang und Einfachheit. Es funktioniert einfach.“