Berikut adalah sebelas opsi untuk mengembalikan baris duplikat di Oracle Database ketika baris tersebut memiliki kunci utama atau kolom pengenal unik lainnya dan Anda ingin mengabaikannya.
Contoh Data
Kami akan menggunakan data berikut untuk contoh kami:
SELECT * FROM Dogs;
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR |
---|---|---|
1 | Kulit | Smith |
2 | Kulit | Smith |
3 | Guk | Jones |
4 | Ruff | Robinson |
5 | Goyang | Johnson |
6 | Goyang | Johnson |
7 | Goyang | Johnson |
Dua baris pertama adalah duplikat dan tiga baris terakhir adalah duplikat. Baris duplikat memiliki nilai yang sama persis di semua kolom dengan pengecualian kolom kunci utama/ID uniknya.
Kolom kunci utama memastikan bahwa tidak ada baris duplikat, yang merupakan praktik yang baik di RDBMS, karena kunci utama membantu menegakkan integritas data. Tetapi fakta bahwa kunci utama berisi nilai unik berarti bahwa kita perlu mengabaikan kolom tersebut saat mencari duplikat.
Dalam tabel kami di atas, kolom kunci utama adalah angka yang bertambah, dan nilainya tidak memiliki arti dan tidak signifikan. Oleh karena itu, kami dapat mengabaikan data kolom tersebut saat mencari duplikat.
Opsi 1
Inilah opsi pertama kami untuk mengembalikan duplikat:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC;
Hasil:
NAMA PERTAMA | NAMA TERAKHIR | COUNT |
---|---|---|
Bergoyang | Johnson | 3 |
Kulit | Smith | 2 |
Ruff | Robinson | 1 |
Guk | Jones | 1 |
Di sini kami membuat kueri dengan GROUP BY
klausa sehingga output dikelompokkan berdasarkan kolom yang relevan. Kami juga menggunakan COUNT()
berfungsi untuk mengembalikan jumlah baris yang identik. Dan kami memesannya dengan menghitung dalam urutan menurun sehingga duplikat muncul lebih dulu.
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
Kita dapat menambahkan HAVING
klausa ke contoh kami sebelumnya untuk mengecualikan non-duplikat dari output:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC;
Hasil:
NAMA PERTAMA | NAMA TERAKHIR | COUNT |
---|---|---|
Bergoyang | Johnson | 3 |
Kulit | Smith | 2 |
Opsi 3
Kami juga dapat memeriksa duplikat pada kolom gabungan. Dalam hal ini kami menggunakan DISTINCT
kata kunci untuk mendapatkan nilai yang berbeda, lalu gunakan COUNT()
berfungsi untuk mengembalikan hitungan:
SELECT
DISTINCT FirstName || ' ' || LastName AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC;
Hasil:
NAMA ANJING | COUNT |
---|---|
Wag Johnson | 3 |
Bark Smith | 2 |
Ruff Robinson | 1 |
Guk Jones | 1 |
Opsi 4
Setiap baris di Oracle memiliki rowid
pseudocolumn yang mengembalikan alamat baris. rowid
adalah pengidentifikasi unik untuk baris dalam tabel, dan biasanya nilainya secara unik mengidentifikasi baris dalam database (walaupun penting untuk dicatat bahwa baris dalam tabel berbeda yang disimpan bersama dalam cluster yang sama dapat memiliki rowid
).
Bagaimanapun, kita dapat membuat kueri yang menggunakan rowid
jika kita mau:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.rowid > d2.rowid
);
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR |
---|---|---|
2 | Kulit | Smith |
6 | Goyang | Johnson |
7 | Goyang | Johnson |
Kita bisa mengganti SELECT *
dengan DELETE
untuk melakukan operasi de-duping di atas meja.
Perhatikan bahwa kita dapat menggunakan DogId
kolom (kunci utama kami) alih-alih rowid
jika kita ingin. Yang mengatakan, rowid
dapat berguna jika Anda tidak dapat menggunakan kolom kunci utama karena alasan tertentu, atau jika tabel tidak memiliki kunci utama.
Opsi 5
Berikut kueri lain yang menggunakan rowid
:
SELECT * FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR |
---|---|---|
2 | Kulit | Smith |
6 | Goyang | Johnson |
7 | Goyang | Johnson |
Seperti contoh sebelumnya, kita dapat mengganti SELECT *
dengan DELETE
untuk menghapus baris duplikat.
Opsi 6
Dua rowid
opsi di atas sangat bagus jika Anda benar-benar harus mengabaikan kunci utama dalam kueri Anda (atau jika Anda tidak memiliki kolom kunci utama sama sekali). Namun seperti yang disebutkan, masih ada opsi untuk mengganti rowid
dengan kolom kunci utama – dalam kasus kami DogId
kolom:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.DogId > d2.DogId
);
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR |
---|---|---|
2 | Kulit | Smith |
6 | Goyang | Johnson |
7 | Goyang | Johnson |
Opsi 7
Dan inilah kueri lainnya dengan rowid
diganti dengan DogId
kolom:
SELECT * FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR |
---|---|---|
2 | Kulit | Smith |
6 | Goyang | Johnson |
7 | Goyang | Johnson |
Opsi 8
Cara lain untuk menemukan duplikat adalah dengan menggunakan ROW_NUMBER()
fungsi jendela:
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs;
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR | ROW_NUM |
---|---|---|---|
1 | Kulit | Smith | 1 |
2 | Kulit | Smith | 2 |
4 | Ruff | Robinson | 1 |
7 | Goyang | Johnson | 1 |
5 | Goyang | Johnson | 2 |
6 | Goyang | Johnson | 3 |
3 | Guk | 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 9
Kami juga dapat menggunakan contoh sebelumnya sebagai ekspresi tabel umum dalam kueri yang lebih besar:
WITH cte AS
(
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs
)
SELECT * FROM cte WHERE row_num <> 1;
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR | ROW_NUM |
---|---|---|---|
2 | Kulit | Smith | 2 |
5 | Goyang | Johnson | 2 |
6 | Goyang | Johnson | 3 |
Kueri tersebut mengecualikan non-duplikat dari keluaran, dan mengecualikan satu baris dari setiap duplikat dari keluaran.
Opsi 10
Berikut cara lain untuk mendapatkan hasil yang sama seperti contoh sebelumnya:
SELECT * FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
Hasil:
DOGID | NAMA PERTAMA | NAMA TERAKHIR |
---|---|---|
2 | Kulit | Smith |
6 | Goyang | Johnson |
7 | Goyang | Johnson |
Contoh ini menggunakan MINUS
Oracle operator, yang hanya mengembalikan baris unik yang dikembalikan oleh kueri pertama tetapi tidak oleh yang kedua.
MINUS
operator mirip dengan EXCEPT
operator di DBMS lain, seperti SQL Server, MariaDB, PostgreSQL, dan SQLite.
Opsi 11
Berikut ini opsi lain untuk memilih duplikat dari tabel kami:
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 | NAMA PERTAMA | NAMA TERAKHIR | DOGID | NAMA PERTAMA | NAMA TERAKHIR |
---|---|---|---|---|---|
2 | Kulit | Smith | 1 | Kulit | Smith |
7 | Goyang | Johnson | 5 | Goyang | Johnson |
7 | Goyang | Johnson | 6 | Goyang | Johnson |