Ekstrak hanya yang pertama dari unit rekaman di mana nilai kolom yang ditentukan diduplikasi

Halaman Diperbarui :
Tanggal pembuatan halaman :

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".

ID1Nama 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.

ID1Nama 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)
)