Berikut adalah tujuh cara untuk mengembalikan baris duplikat di MySQL ketika baris tersebut memiliki kunci utama atau kolom pengenal unik lainnya.
Contoh Data
Kami akan menggunakan data berikut untuk contoh kami:
DROP TABLE IF EXISTS Dogs;
CREATE TABLE Dogs (
DogId int PRIMARY KEY NOT NULL,
FirstName varchar(50),
LastName varchar(50)
);
INSERT INTO Dogs VALUES
(1, 'Bark', 'Smith'),
(2, 'Bark', 'Smith'),
(3, 'Woof', 'Jones'),
(4, 'Ruff', 'Robinson'),
(5, 'Wag', 'Johnson'),
(6, 'Wag', 'Johnson'),
(7, 'Wag', 'Johnson');
SELECT * FROM Dogs;
Hasil:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 1 | Bark | Smith | | 2 | Bark | Smith | | 3 | Woof | Jones | | 4 | Ruff | Robinson | | 5 | Wag | Johnson | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Baris duplikat memiliki nilai yang sama persis di semua kolom kecuali untuk kunci utama/kolom ID uniknya.
Dua baris pertama adalah duplikat (kecuali untuk DogId
kolom, yang merupakan kunci utama tabel, dan berisi nilai unik di semua baris). Tiga baris terakhir juga merupakan duplikat (kecuali untuk DogId
kolom).
Kolom kunci utama memastikan bahwa tidak ada baris duplikat, yang biasanya merupakan hal yang baik di RDBMS. Namun, menurut definisi ini berarti tidak ada duplikat. Dalam kasus kami, kolom kunci utama adalah angka yang bertambah, dan nilainya tidak memiliki arti dan tidak signifikan. Oleh karena itu, kita perlu mengabaikan baris tersebut jika ingin menemukan duplikat di kolom yang adalah penting.
Opsi 1
Opsi pertama kami adalah menggunakan GROUP BY
klausa untuk mengelompokkan kolom menurut kolom signifikannya, lalu gunakan COUNT()
fungsi untuk mengembalikan jumlah baris identik:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Hasil:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Wag | Johnson | 3 | +-----------+----------+-------+
Kami dapat mengabaikan kolom kunci utama dengan menghilangkannya dari kueri kami.
Hasilnya memberi tahu kita bahwa ada dua baris berisi Bark Smith dan tiga baris berisi Wag Johnson. Ini adalah duplikat (atau rangkap tiga dalam kasus Wag Johnson). Dua baris lainnya tidak memiliki duplikat.
Opsi 2
Kami dapat mengecualikan non-duplikat dari output dengan HAVING
klausa:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Hasil:
+-----------+----------+-------+ | FirstName | LastName | Count | +-----------+----------+-------+ | Bark | Smith | 2 | | Wag | Johnson | 3 | +-----------+----------+-------+
Opsi 3
Kami juga dapat memeriksa duplikat pada kolom gabungan. Misalnya, kita dapat menggunakan CONCAT()
fungsi untuk menggabungkan dua kolom kami, gunakan DISTINCT
kata kunci untuk mendapatkan nilai yang berbeda, lalu gunakan COUNT()
berfungsi untuk mengembalikan hitungan:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Hasil:
+---------------+-------+ | DogName | Count | +---------------+-------+ | Bark Smith | 2 | | Woof Jones | 1 | | Ruff Robinson | 1 | | Wag Johnson | 3 | +---------------+-------+
Opsi 4
Sebagai alternatif, kita dapat menggunakan ROW_NUMBER()
fungsi dengan PARTITION BY
klausa:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS rn
FROM Dogs;
Hasil:
+-------+-----------+----------+----+ | DogId | FirstName | LastName | rn | +-------+-----------+----------+----+ | 1 | Bark | Smith | 1 | | 2 | Bark | Smith | 2 | | 4 | Ruff | Robinson | 1 | | 5 | Wag | Johnson | 1 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | | 3 | Woof | Jones | 1 | +-------+-----------+----------+----+
Ini membuat kolom baru dengan nomor baris yang bertambah setiap kali ada duplikat, tetapi disetel ulang lagi saat ada baris unik
Teknik ini memberikan kemungkinan manfaat karena kita tidak perlu mengelompokkan hasilnya. Ini berarti kita dapat melihat setiap baris duplikat, termasuk kolom pengenal uniknya.
Opsi 5
Kita dapat menggunakan contoh sebelumnya sebagai ekspresi tabel umum dalam kueri yang lebih besar:
WITH cte AS
(
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS rn
FROM Dogs
)
SELECT * FROM cte WHERE rn <> 1;
Hasil:
+-------+-----------+----------+----+ | DogId | FirstName | LastName | rn | +-------+-----------+----------+----+ | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +-------+-----------+----------+----+
Teknik ini mengecualikan non-duplikat dari output, dan mengecualikan satu baris dari setiap duplikat dari output.
Kueri ini dapat digunakan sebagai pendahulu untuk operasi de-duping. Itu dapat menunjukkan kepada kita apa yang akan dihapus jika kita memutuskan untuk menghapus duplikat. Untuk menghilangkan penipuan tabel, yang perlu kita lakukan hanyalah mengganti SELECT *
. yang terakhir dengan DELETE
.
Opsi 6
Berikut cara yang lebih ringkas untuk mendapatkan hasil yang sama seperti contoh sebelumnya:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName)
);
Hasil:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Teknik ini tidak mengharuskan kita untuk membuat nomor baris terpisah dengan ROW_NUMBER()
seperti pada contoh sebelumnya.
Kami juga dapat mengganti SELECT *
dengan DELETE
untuk menghapus duplikat.
Opsi 7
Dan terakhir, inilah satu opsi lagi untuk mengembalikan duplikat:
SELECT *
FROM Dogs d1, Dogs d2
WHERE d1.FirstName = d2.FirstName
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId
AND d1.DogId = (
SELECT MAX(DogId)
FROM Dogs d3
WHERE d3.FirstName = d1.FirstName
AND d3.LastName = d1.LastName
);
Hasil:
+-------+-----------+----------+-------+-----------+----------+ | DogId | FirstName | LastName | DogId | FirstName | LastName | +-------+-----------+----------+-------+-----------+----------+ | 2 | Bark | Smith | 1 | Bark | Smith | | 7 | Wag | Johnson | 5 | Wag | Johnson | | 7 | Wag | Johnson | 6 | Wag | Johnson | +-------+-----------+----------+-------+-----------+----------+