Berikut adalah tujuh cara untuk mengembalikan baris duplikat di PostgreSQL ketika baris tersebut memiliki kunci utama atau kolom pengenal unik lainnya.
Ini berarti bahwa baris duplikat memiliki nilai yang sama persis di semua kolom dengan pengecualian kolom kunci utama/ID uniknya.
Contoh Data
Kami akan menggunakan data berikut untuk contoh kami:
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
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 merupakan praktik yang baik di RDBMS, karena kunci utama membantu menegakkan integritas data. Tetapi karena kunci utama mencegah baris duplikat, mereka berpotensi mengganggu kemampuan kita untuk menemukan duplikat.
Dalam tabel kami di atas, kolom kunci utama adalah angka yang bertambah, dan nilainya tidak memiliki arti dan tidak signifikan. Oleh karena itu, kita perlu mengabaikan baris itu jika ingin menemukan duplikat di kolom lain.
Opsi 1
Kita dapat menggunakan SQL 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 -----------+----------+------- Ruff | Robinson | 1 Wag | Johnson | 3 Woof | Jones | 1 Bark | Smith | 2
Di sini kami mengecualikan kolom kunci utama 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). 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 -----------+----------+------- Wag | Johnson | 3 Bark | Smith | 2
Opsi 3
Berikut adalah contoh pemeriksaan duplikat pada kolom gabungan. Dalam hal ini kita 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 ---------------+------- Wag Johnson | 3 Ruff Robinson | 1 Woof Jones | 1 Bark Smith | 2
Opsi 4
Sebagai alternatif, kita dapat menggunakan ROW_NUMBER()
fungsi jendela:
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
Menggunakan PARTITION
klausa menghasilkan kolom baru yang ditambahkan, dengan nomor baris yang bertambah setiap kali ada duplikat, tetapi disetel ulang lagi saat ada baris unik.
Dalam hal ini kami tidak mengelompokkan hasilnya, yang berarti kami dapat melihat setiap baris duplikat, termasuk kolom pengenal uniknya.
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
Ini mengecualikan non-duplikat dari output, dan mengecualikan satu baris dari setiap duplikat dari output. Dengan kata lain, itu hanya menunjukkan kelebihan baris dari duplikat. Baris ini adalah kandidat utama untuk dihapus dalam operasi de-duping.
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 -------+-----------+---------- 6 | Wag | Johnson 2 | Bark | Smith 7 | Wag | Johnson
Satu perbedaan antara contoh ini dan yang sebelumnya adalah bahwa contoh ini tidak memerlukan pembuatan nomor baris terpisah kita sendiri.
Opsi 7
Berikut ini opsi lain untuk mengembalikan baris duplikat di Postgres:
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