🧚 Hör mal! Beekeeper Studio ist eine schnelle, moderne und Open-Source-Datenbank-GUI Download
7. Januar 2026 Von Matthew Rathbone

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 keepers ist für MySQL gedacht, das einem DELETE sonst 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- oder ROW_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:

Offizielle Dokumentation:

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.

Die Linux-Version von Beekeeper hat 100% des Funktionsumfangs, ohne Abstriche und ohne Kompromisse.

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.“
— Alex K., Datenbankentwickler
★★★★★
„Ich habe viele Datenbank-GUIs ausprobiert, aber Beekeeper trifft die perfekte Balance zwischen Funktionsumfang und Einfachheit. Es funktioniert einfach.“
— Sarah M., Full-Stack-Entwicklerin

Bereit, deinen SQL-Workflow zu verbessern?

download Kostenlos herunterladen