Ekstrak hanya yang pertama daripada unit rekod di mana nilai lajur yang ditentukan diduplikasi
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)
)