Ekstrak hanya yang pertama dari unit rekaman di mana nilai kolom yang ditentukan diduplikasi
Biasanya, ketika mengekstrak hanya satu rekaman duplikat, hal pertama yang terlintas dalam pikiran saya adalah distinct
saya berpikir,
distinct
tidak mengizinkan Anda menentukan kolom duplikat dan kolom lain yang ingin Anda ambil secara bersamaan.
Selain itu,distinct
tidak sesuai dengan persyaratan ini karena menyertakan catatan non-duplikat dalam ekstraksi.
Saya rasa Anda tidak dapat memahami apa yang ingin Anda lakukan dengan judul saja, jadi mari kita gunakan contoh rekaman sebagai contoh. Yang ingin saya lakukan adalah hasil ekstraksi berikut.
Nama | ID |
---|---|
1 | Nama 1 |
2 | Nama 2 |
3 | Nama 3 |
3 | Nama 3@example.com |
4 | Nama 4 Nama 4@example.com |
4 | Nama 4@example.com |
4 | Nama 4@example.com |
Dapatkan sebagai berikut:
Nama | ID |
---|---|
3 | Nama 3@example.com |
4 | Nama 4@example.com |
ID 1 dan 2 tidak disertakan karena bukan duplikat. ID 3 dan 4 adalah duplikat, jadi salah satunya diambil. Namun, kali ini, kita tidak akan mendapatkan catatan pertama dalam urutan penyimpanan DB. Selain itu, misalkan Anda menginginkan baris pertama nama dalam urutan prioritas dengan kondisi bahwa "Nama berisi tanda @" dan "Nama memiliki sejumlah kecil karakter".
Kondisi di atas dapat diperoleh dengan SQL berikut. Namun, kami menggunakan subkueri dan belum memeriksa kinerjanya.
select
*
from
(select *, row_number() over(order by ID asc) as RowNum from SampleTable) tableMain
where tableMain.RowNum =
(
select
top(1) RowNum
from
(select *, row_number() over(order by ID asc) as RowNum from SampleTable) tableSub
where
tableMain.ID = tableSub.ID
and exists (
select
*
from
SampleTable
where
tableSub.ID = ID
having
count(*) >= 2
)
order by
case when charindex(N'@', Name) >= 1 then 0 else 1 end, len(Name)
)
Baris duplikat diperiksa having
dengan dan . count
group by
Kolom kunci yang akan diperiksa dari luar, di sini ID
kolom dipersempit where
oleh .
Urutan prioritas untuk mengambil baris pertama ditentukan order by
oleh . charindex
Di sini, dan len
periksa apakah itu berisi karakter yang ditentukan dan panjang string.
top
Yang perlu Anda lakukan adalah mendapatkan baris pertama dari setiap rekaman duplikat di .
Awalnya, ini baik-baik saja, tetapi jika ada dua atau lebih catatan dengan nilai yang persis sama, seperti "ID: 4, Nama: Nama 4@example.com", Anda pasti akan mendapatkan dua catatan.
row_number
Oleh karena itu, ditambahkan sehingga dapat diidentifikasi untuk setiap baris dengan , sehingga hanya satu catatan dengan nilai yang persis sama yang dapat diambil.
Jika diketahui bahwa catatan yang sama persis tidak ada, saya row_number
pikir akan lebih baik untuk memeriksa nilai catatan yang ada tanpa menambahkan .
Jika ada beberapa kunci yang harus diperiksa untuk duplikat, Anda dapat meningkatkan jumlah kolom kunci untuk masing-masing kolom. Misalnya, pertimbangkan catatan berikut: Kolom yang akan diperiksa untuk duplikat adalah "ID1" dan "ID2".
ID1 | Nama | ID2 |
---|---|---|
1 | 1 | Nama 1 |
2 | 1 | Nama 2 |
3 | 1 | Nama 31 |
3 | 2 | Nama 32 |
4 | 1 | Nama41 |
4 | 2 | Nama42 |
4 | 2 | Nama 4@example.com |
5 | 1 | Nama 555@example.com |
5 | 1 | Nama 55@example.com |
5 | 2 | Nama 5@example.com |
6 | 1 | Nama 6 |
6 | 1 | Nama 66@example.com |
6 | 2 | Nama 6 |
6 | 2 | Nama 6 |
Hasil akuisisi adalah sebagai berikut.
ID1 | Nama | ID2 |
---|---|---|
4 | 2 | Nama 4@example.com |
5 | 1 | Nama 55@example.com |
6 | 1 | Nama 66@example.com |
6 | 2 | Nama 6 |
SQL terlihat seperti ini: Anda cukup menambah bagian di mana kolom kunci ditentukan.
select
*
from
(select *, row_number() over(order by ID1 asc, ID2 asc) as RowNum from SampleTable) tableMain
where tableMain.RowNum =
(
select
top(1) RowNum
from
(select *, row_number() over(order by ID1 asc, ID2 asc) as RowNum from SampleTable) tableSub
where
tableMain.ID1 = tableSub.ID1
and tableMain.ID2 = tableSub.ID2
and exists (
select
*
from
SampleTable
where
tableSub.ID1 = ID1
and tableSub.ID2 = ID2
having
count(*) >= 2
)
order by
case when charindex(N'@', Name) >= 1 then 0 else 1 end, len(Name)
)