🧚 Dengar! Beekeeper Studio adalah GUI database yang cepat, modern, dan open source Unduh
7 Januari 2026 Oleh Matthew Rathbone

Menghapus duplikat di SQL berarti salah satu dari dua hal: menyembunyikan baris berulang dari hasil query dengan DISTINCT, atau menghapus salinan berlebih dari tabel sehingga tersisa satu dari masing-masing. Contoh-contohnya berfungsi di PostgreSQL, MySQL, SQLite, dan SQL Server.

Cara menghapus duplikat di SQL

SELECT DISTINCT mengembalikan setiap kombinasi kolom yang disebutkan satu kali saja dan tidak mengubah tabel. Untuk membersihkan tabelnya sendiri, hapus semua baris kecuali satu di setiap kelompok duplikat, biasanya yang id-nya paling kecil:

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
);

Di sini Maria Lopez dimasukkan tiga kali:

-- 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

Aturan yang perlu diketahui

  • Sebutkan kolom yang membuat dua baris dianggap duplikat. Jangan sertakan id dan kolom lain yang selalu berbeda, seperti timestamp created_at. Baris yang berbeda di salah satu kolom yang disebutkan akan tetap disimpan semuanya.
  • Pembungkus SELECT id FROM (...) AS keepers diperlukan untuk MySQL, yang kalau tidak akan menolak DELETE membaca tabelnya sendiri di dalam subquery: “You can’t specify target table ‘customers’ for update in FROM clause”.
  • Periksa dulu sebelum menghapus. Jalankan query GROUP BY atau ROW_NUMBER() terlebih dahulu untuk melihat apa yang akan terhapus, dan lakukan penghapusan di dalam transaksi yang bisa di-rollback.
  • Cegah duplikat baru dengan unique index setelah tabel bersih:
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"

Sintaks alternatif

Di kode SQL Server, Anda akan sering melihat salinan diberi nomor di dalam CTE lalu dihapus melalui CTE tersebut, yang hanya diizinkan oleh SQL Server. Pada tabel customers asli:

-- 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

Untuk menggabungkan dua query tanpa baris berulang, gunakan UNION, yang menghapus duplikat, bukan UNION ALL, yang mempertahankannya:

SELECT 'apple' AS fruit UNION ALL SELECT 'apple';

-- Output:
-- fruit
-- -----
-- apple
-- apple

SELECT 'apple' AS fruit UNION SELECT 'apple';
-- Output: apple

Kapan sebaiknya Anda menghapus duplikat?

Terkadang Anda hanya perlu menyembunyikan pengulangan di hasil query, dan terkadang tabelnya sendiri yang perlu dibersihkan. Berikut langkah-langkah yang biasa dilakukan, dari memeriksa hingga menghapus.

Tampilkan setiap nilai sekali

Untuk laporan, dropdown, atau sekadar mengecek isi sebuah kolom, SELECT DISTINCT membuang pengulangan dari hasil dan membiarkan tabel apa adanya.

Hitung salinan sebelum menghapus

Kelompokkan berdasarkan kolom yang menentukan duplikat dan pertahankan kelompok dengan HAVING COUNT(*) > 1. Cara ini menunjukkan apa yang terduplikasi dan berapa kali, sebelum ada yang dihapus. Panduan mencari duplikat di SQL membahas lebih banyak cara untuk memeriksanya.

Pilih salinan yang dipertahankan

ROW_NUMBER() memberi nomor pada baris di setiap kelompok duplikat. ORDER BY di dalam OVER (...) menentukan baris mana yang mendapat nomor 1 dan dipertahankan: yang paling lama, paling baru, atau paling lengkap.

Hapus salinan berlebih

Setelah tahu baris mana yang dipertahankan, hapus sisanya. Untuk mempertahankan baris terbaru alih-alih yang terlama, beri nomor baris berdasarkan tanggal, mulai dari yang terbaru, lalu hapus semua yang bernomor di atas 1.

Contoh nyata menghapus duplikat

Semua negara dan kurir pengiriman Anda

DISTINCT berlaku untuk seluruh baris dari kolom yang dipilih, jadi Kanada muncul sekali untuk setiap kurir:

-- 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

Alamat email yang hanya berbeda huruf besar-kecil

Kelompokkan berdasarkan email dalam huruf kecil agar Jon@Example.com dan jon@example.com dihitung sebagai salinan. (MySQL dan SQL Server secara default sudah mengabaikan huruf besar-kecil, dan LOWER() tidak berdampak buruk di sana.)

-- 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

Pertahankan salinan yang punya nomor telepon

Urutkan baris yang memiliki nomor telepon lebih dulu, lalu berdasarkan id, sehingga baris paling lengkap di setiap kelompok mendapat nomor 1:

-- 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

Menghapus baris bernomor 2 atau lebih (id 1 dan 4) menyisakan satu kontak lengkap per email.

Hapus salinan identik dari tabel tanpa id

Jika salinannya identik di semua kolom, tidak ada id terkecil yang bisa dipertahankan. Salin baris-baris distinct ke tabel baru lalu tukar dengan tabel lama. Tambahkan kembali index dan constraint yang dimiliki tabel lama, karena salinannya tidak membawanya:

-- 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

Bacaan lanjutan tentang menghapus duplikat

Di blog ini:

Dokumentasi resmi:

Beekeeper Studio Adalah GUI Database Gratis & Open Source

Tool query & editor SQL terbaik yang pernah saya pakai. Semua yang saya butuhkan untuk mengelola database ada di sini. - ⭐⭐⭐⭐⭐ Mit

Beekeeper Studio cepat, intuitif, dan mudah digunakan. Beekeeper mendukung banyak sekali database, dan berjalan mulus di Windows, Mac, dan Linux.

Versi Linux Beekeeper punya fitur 100% lengkap, tanpa potong kompas, tanpa kompromi fitur.

Apa Kata Pengguna Tentang Beekeeper Studio

★★★★★
"Beekeeper Studio sepenuhnya menggantikan alur kerja SQL lama saya. Cepat, intuitif, dan membuat pekerjaan database kembali menyenangkan."
— Alex K., Database Developer
★★★★★
"Saya sudah mencoba banyak GUI database, tetapi Beekeeper punya keseimbangan sempurna antara fitur dan kesederhanaan. Langsung berfungsi."
— Sarah M., Full Stack Engineer

Siap Meningkatkan Alur Kerja SQL Anda?

download Unduh Gratis