Extraheer alleen de eerste uit de recordeenheid waar de waarde van de opgegeven kolom wordt gedupliceerd

Pagina bijgewerkt :
Aanmaakdatum van pagina :

Normaal gesproken, bij het extraheren van slechts één duplicaat record, is distinct het eerste dat in me opkomt dat ik denk: distinct Hiermee kunt u niet tegelijkertijd een dubbele kolom en een andere kolom opgeven die u wilt ophalen. Bovendiendistinct voldoet het niet aan deze vereiste omdat het niet-dubbele records in de extractie opneemt.

Ik denk niet dat je kunt begrijpen wat je met de titel alleen wilt doen, dus laten we een voorbeeldplaat als voorbeeld nemen. Wat ik wil doen is het volgende extractieresultaat.

ID Naam
1 Naam 1
2 Naam 2
3 Naam 3
3 Naam 3@example.com
4 Naam 4 Naam 4@example.com
4 Naam 4@example.com
4 Naam 4@example.com

Krijg het als volgt:

ID Naam
3 Naam 3@example.com
4 Naam 4@example.com

ID's 1 en 2 zijn niet opgenomen omdat het geen duplicaten zijn. ID's 3 en 4 zijn duplicaten, dus een ervan wordt opgehaald. Deze keer krijgen we echter niet de eerste record in de DB-opslagorder. Stel daarnaast dat u de eerste regel van de naam in volgorde van prioriteit wilt hebben onder de voorwaarden dat "Naam bevat een @-teken" en "Naam heeft een klein aantal tekens".

Bovenstaande voorwaarde kan worden verkregen met de volgende SQL. We maken echter gebruik van subquery's en hebben de prestaties niet gecontroleerd.

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

Dubbele rijen worden having aangevinkt met en count . group by De belangrijkste kolom die van buitenaf moet worden gecontroleerd, hier ID wordt where de kolom versmald door .

De volgorde van prioriteit voor het ophalen van de eerste rij wordt order by aangegeven door . charindex Hier, en len controleer of het het opgegeven teken en de lengte van de tekenreeks bevat. top Het enige dat u hoeft te doen, is de eerste rij van elk dubbel record in .

Oorspronkelijk is dit prima, maar als er twee of meer records zijn met exact dezelfde waarde, zoals "ID: 4, Name: Name 4@example.com", krijg je onvermijdelijk twee records. row_number Daarom wordt het toegevoegd zodat het voor elke rij kan worden geïdentificeerd met , zodat slechts één record met exact dezelfde waarde kan worden opgehaald. Als bekend is dat exact hetzelfde record niet bestaat, denk ik row_number dat het beter is om de waarden van de bestaande records te controleren zonder toe te voegen.

Als er meerdere sleutels zijn die op duplicaten moeten worden gecontroleerd, kunt u het aantal sleutelkolommen voor elke sleutel verhogen. Neem bijvoorbeeld de volgende record: De kolommen die op duplicaten moeten worden gecontroleerd, zijn "ID1" en "ID2".

ID1 ID2 Naam
1 1 Naam 1
2 1 Naam 2
3 1 Naam 31
3 2 Naam 32
4 1 Naam41
4 2 Naam42
4 2 Naam 4@example.com
5 1 Naam 555@example.com
5 1 Naam 55@example.com
5 2 Naam 5@example.com
6 1 Naam 6
6 1 Naam 66@example.com
6 2 Naam 6
6 2 Naam 6

Het overnameresultaat is als volgt.

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

De SQL ziet er als volgt uit: U kunt eenvoudig het gedeelte vergroten waar de sleutelkolom is opgegeven.

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