Ekstrak hanya yang pertama daripada unit rekod di mana nilai lajur yang ditentukan diduplikasi

Laman dikemaskini :
Tarikh penciptaan halaman :

Biasanya, apabila mengekstrak hanya satu rekod pendua, perkara pertama yang terlintas di fikiran ialah distinct saya fikir, distinct tidak membenarkan anda menentukan lajur pendua dan lajur lain yang anda mahu dapatkan semula pada masa yang sama. Di samping itu,distinct tidak sepadan dengan keperluan ini kerana ia termasuk rekod bukan pendua dalam pengekstrakan.

Saya rasa anda tidak boleh memahami apa yang anda mahu lakukan dengan tajuk sahaja, jadi mari gunakan rekod sampel sebagai contoh. Apa yang saya mahu lakukan ialah hasil pengekstrakan 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 seperti berikut:

Nama ID
3 Nama 3@example.com
4 Nama 4@example.com

ID 1 dan 2 tidak disertakan kerana ia bukan pendua. ID 3 dan 4 adalah pendua, jadi salah satu daripadanya diambil. Walau bagaimanapun, kali ini, kami tidak akan mendapat rekod pertama dalam pesanan storan DB. Di samping itu, katakan anda mahukan baris pertama nama mengikut keutamaan di bawah syarat bahawa "Nama mengandungi tanda @" dan "Nama mempunyai sebilangan kecil aksara".

Syarat di atas boleh diperolehi dengan SQL berikut. Walau bagaimanapun, kami menggunakan subpertanyaan dan belum menyemak prestasi.

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 pendua disemak having dengan dan count . group by Lajur utama yang perlu diperiksa dari luar, di sini ID lajur disempitkan where oleh .

Susunan keutamaan untuk mendapatkan semula baris pertama ditentukan order by oleh . charindex Di sini, dan len semak sama ada ia mengandungi aksara yang ditentukan dan panjang rentetan. top Apa yang anda perlu lakukan ialah mendapatkan baris pertama setiap rekod pendua dalam .

Pada asalnya, ini tidak mengapa, tetapi jika terdapat dua atau lebih rekod dengan nilai yang sama, seperti "ID: 4, Nama: Nama 4@example.com", anda pasti akan mendapat dua rekod. row_number Oleh itu, ia dilampirkan supaya ia boleh dikenal pasti untuk setiap baris dengan , supaya hanya satu rekod dengan nilai yang sama boleh diambil. Jika diketahui bahawa rekod yang sama tidak wujud, saya row_number rasa lebih baik untuk menyemak nilai rekod sedia ada tanpa menambah.

Jika terdapat berbilang kekunci yang perlu disemak untuk pendua, anda boleh meningkatkan bilangan lajur kunci untuk setiap satu. Sebagai contoh, pertimbangkan rekod berikut: Lajur yang akan disemak untuk pendua ialah "ID1" dan "ID2".

ID1 ID2 Nama
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 pemerolehan adalah seperti berikut.

ID1 ID2 Nama
4 2 Nama 4@example.com
5 1 Nama 55@example.com
6 1 Nama 66@example.com
6 2 Nama 6

SQL kelihatan seperti ini: Anda hanya boleh menambah bahagian di mana lajur kunci telah 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)
)