Berikut adalah tujuh opsi untuk menemukan baris duplikat di SQL Server, ketika baris tersebut memiliki kunci utama atau kolom pengenal unik lainnya.
Dengan kata lain, tabel berisi dua atau lebih baris yang memiliki nilai yang sama persis di semua kolom kecuali untuk kolom pengenal uniknya.
Contoh Data
Misalkan kita memiliki tabel dengan data berikut:
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 | +---------+-------------+------------+
Kita dapat melihat bahwa dua baris pertama adalah duplikat (kecuali untuk DogId
kolom, yang berisi nilai unik di semua baris, dan dapat digunakan sebagai kolom kunci utama tabel). Kita juga dapat melihat bahwa tiga baris terakhir adalah duplikat (kecuali untuk DogId
kolom).
Kolom ID unik memastikan bahwa tidak ada baris duplikat, yang biasanya merupakan sifat yang sangat diinginkan dalam RDBMS. Namun, dalam hal ini berpotensi mengganggu kemampuan kami untuk menemukan duplikat. Menurut definisi, kolom ID unik memastikan bahwa tidak ada duplikat. Untungnya, kami dapat mengatasi masalah ini dengan cukup mudah, seperti yang ditunjukkan oleh contoh berikut.
Opsi 1
Mungkin cara termudah/tersederhana untuk melakukannya adalah dengan kueri sederhana yang menggunakan GROUP BY
klausa:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;
Hasil:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Woof | Jones | 1 | | Ruff | Robinson | 1 | | Bark | Smith | 2 | +-------------+------------+---------+
Kami dapat mengecualikan kunci utama/kolom ID unik dengan menghilangkannya dari kueri kami.
Hasilnya memberi tahu kita bahwa ada tiga baris berisi Wag Johnson dan dua baris berisi Bark Smith. Ini adalah duplikat (atau rangkap tiga dalam kasus Wag Johnson).
Opsi 2
Kami dapat mengecualikan non-duplikat dari hasil dengan menyertakan HAVING
klausa dalam kueri kami:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;
Hasil:
+-------------+------------+---------+ | FirstName | LastName | Count | |-------------+------------+---------| | Wag | Johnson | 3 | | Bark | Smith | 2 | +-------------+------------+---------+
Opsi 3
Kami juga dapat memeriksa duplikat pada kolom gabungan. Misalnya, kita dapat menggunakan CONCAT()
fungsi untuk menggabungkan dua kolom kami:
SELECT
DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);
Hasil:
+---------------+---------+ | DogName | Count | |---------------+---------| | Bark Smith | 2 | | Ruff Robinson | 1 | | Wag Johnson | 3 | | Woof Jones | 1 | +---------------+---------+
Opsi 4
Kita dapat menggunakan ROW_NUMBER()
fungsi dengan PARTITION BY
klausa untuk membuat kolom baru dengan nomor baris yang bertambah setiap kali ada duplikat, tetapi disetel ulang lagi ketika ada baris unik:
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS Row_Number
FROM Dogs;
Hasil:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 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 | +---------+-------------+------------+--------------+
Salah satu manfaat dari metode ini adalah kita dapat melihat setiap baris duplikat, beserta kolom pengenal uniknya, karena kita tidak mengelompokkan hasilnya.
Opsi 5
Kami juga 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 Row_Number
FROM Dogs
)
SELECT * FROM cte WHERE Row_Number <> 1;
Hasil:
+---------+-------------+------------+--------------+ | DogId | FirstName | LastName | Row_Number | |---------+-------------+------------+--------------| | 2 | Bark | Smith | 2 | | 6 | Wag | Johnson | 2 | | 7 | Wag | Johnson | 3 | +---------+-------------+------------+--------------+
Opsi ini mengecualikan non-duplikat dari output.
Itu juga mengecualikan tepat satu baris dari setiap duplikat dari output. Ini membuka pintu bagi kita untuk memutar SELECT *
last terakhir menjadi DELETE
untuk menghilangkan penipuan tabel sambil menyimpan satu dari setiap duplikat.
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
EXCEPT SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Hasil:
+-------+-----------+----------+ | DogId | FirstName | LastName | +-------+-----------+----------+ | 2 | Bark | Smith | | 6 | Wag | Johnson | | 7 | Wag | Johnson | +-------+-----------+----------+
Contoh ini tidak memerlukan pembuatan nomor baris terpisah kita sendiri.
Opsi 7
Dan akhirnya, inilah teknik yang sedikit lebih rumit untuk mengembalikan baris 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 | +---------+-------------+------------+---------+-------------+------------+
Bahkan hasilnya terlihat lebih berbelit-belit, tapi hei, itu masih menunjukkan kepada kita duplikatnya!