Udtræk kun den første fra den postenhed, hvor værdien af den angivne kolonne er duplikeret
Normalt, når man kun udtrækker én duplikatpost, er det første, der kommer til at tænke på, at distinct
jeg tænker:
distinct
Giver dig ikke mulighed for at angive en dubletkolonne og en anden kolonne, som du vil hente på samme tid.
Derudover opfylder ikke dette krav,distinct
fordi det inkluderer ikke-duplikerede poster i udtrækningen.
Jeg tror ikke, du kan forstå, hvad du vil gøre med titlen alene, så lad os bruge en eksempelpost som eksempel. Det, jeg vil gøre, er følgende ekstraktionsresultat.
ID-navn | |
---|---|
1 | Navn 1 |
2 | Navn 2 |
3 | Navn 3 |
3 | Navn 3@example.com |
4 | Navn 4 Navn 4@example.com |
4 | Navn 4@example.com |
4 | Navn 4@example.com |
Få det som følger:
ID-navn | |
---|---|
3 | Navn 3@example.com |
4 | Navn 4@example.com |
ID 1 og 2 er ikke inkluderet, fordi de ikke er dubletter. ID 3 og 4 er dubletter, så en af dem hentes. Denne gang får vi dog ikke den første post i DB-lagerrækkefølgen. Antag desuden, at du vil have den første linje i navnet i prioriteret rækkefølge under de betingelser, at "Navn indeholder et @-mærke" og "Navn har et lille antal tegn".
Ovenstående betingelse kan opnås med følgende SQL. Vi bruger dog underforespørgsler og har ikke kontrolleret ydeevnen.
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)
)
Dubletrækker kontrolleres having
med og count
. group by
Nøglekolonnen skal kontrolleres udefra, her ID
er where
kolonnen indsnævret med .
Rangfølgen for hentning af den første række er order by
angivet med . charindex
Her og len
kontroller, om den indeholder det angivne tegn og længden af strengen.
top
Alt du skal gøre er at få den første række af hver dubletpost ind i .
Oprindeligt er dette fint, men hvis der er to eller flere poster med nøjagtig samme værdi, såsom "ID: 4, Name: Name 4@example.com", vil du uundgåeligt få to poster.
row_number
Derfor tilføjes den, så den kan identificeres for hver række med , så der kun kan hentes én post med nøjagtig samme værdi.
Hvis det er kendt, at nøjagtig den samme post ikke eksisterer, tror jeg row_number
, det ville være bedre at kontrollere værdierne af de eksisterende poster uden at tilføje .
Hvis der er flere nøgler, der skal kontrolleres for dubletter, kan du øge antallet af nøglekolonner for hver. Overvej f.eks. følgende post: De kolonner, der skal kontrolleres for dubletter, er "ID1" og "ID2".
ID1 | ID2 | Navn |
---|---|---|
1 | 1 | Navn 1 |
2 | 1 | Navn 2 |
3 | 1 | Navn 31 |
3 | 2 | Navn 32 |
4 | 1 | Navn41 |
4 | 2 | Navn42 |
4 | 2 | Navn 4@example.com |
5 | 1 | Navn 555@example.com |
5 | 1 | Navn 55@example.com |
5 | 2 | Navn 5@example.com |
6 | 1 | Navn 6 |
6 | 1 | Navn 66@example.com |
6 | 2 | Navn 6 |
6 | 2 | Navn 6 |
Resultatet af opkøbet er som følger.
ID1 | ID2 | Navn |
---|---|---|
4 | 2 | Navn 4@example.com |
5 | 1 | Navn 55@example.com |
6 | 1 | Navn 66@example.com |
6 | 2 | Navn 6 |
SQL ser sådan ud: Du kan blot øge den del, hvor nøglekolonnen blev angivet.
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)
)