SQL DISTINCT og TOP i samme forespørgsel

Denne artikel er inspireret af en række spørgsmål, som en af mine læsere, Nan, for nylig sendte mig vedrørende DISTINCT, TOP og ORDER BY.

Alle eksempler i denne lektion er baseret på Microsoft SQL Server Management Studio og AdventureWorks2012-databasen. Du kan komme i gang med at bruge disse gratis værktøjer ved hjælp af min vejledning Kom godt i gang med at bruge SQL Server.

Hvordan arbejder SQL Top og Distinct SELECT-modifikatorerne sammen for at producere resultater?

Her er det spørgsmål, som Nan oprindeligt sendte mig:

Jeg er lidt forvirret omkring SELECT DISTINCT og SELECT. For eksempel,

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Er dette at se på forskellige fornavne? Distinct kombineret for- og efternavn? Hvordan skelner vi mellem de kolonner, der bruges til den distinkte evaluering, og kolonner, som vi bare vil vise i output?

Hvad med

Select Distinct TOP 10 LastName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName

Jeg tænkte, at alle gerne ville kende svaret, så jeg opretter et blogindlæg.

DISTINCT og TOP – Hvilken er først?

Lad os se på den første anvisning, hvis formål er at returnere en unik liste over for- og efternavne.

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName;

TOP 10 vil returnere de første ti elementer fra den ordnede mængde, og DISTINCT vil fjerne eventuelle dubletter. Spørgsmålet er, hvad der sker først?

  • Er tabellen sorteret efter Efternavn, og de ti øverste elementer tages frem, og derefter fjernes dubletterne?
  • Og fjernes dubletterne, og derefter sorteres elementerne, og de ti øverste elementer vises?

Hvor vi besvarer dette spørgsmål, skal du huske, at DISTINCT opererer på alle kolonner og udtryk i SELECT-klausulen. Så i dette tilfælde vil erklæringen returnere forskellige rækker for FirstName og LastName.

Der er desværre ikke nogen direkte måde at bruge DISTINCT på et sæt felter og vise andre. Når du tilføjer kolonner til SELECT-erklæringen, bliver de under indflydelse af DISTINCT-operatoren. Jeg siger direkte, da du kunne få en distinkt liste, og derefter bruge en INNER JOIN til at trække andre kolonner ind. Der er dog farer ved at gøre det, da join’et kan genindføre dubletter.

Det er interessant at tilføje en TOP-klausul til DISTINCT. Jeg var ikke sikker på, hvad der ville ske, men jeg eksperimenterede lidt med AdventureWorks-databasen og fandt ud af, at rækkefølgen af behandlingen går nogenlunde sådan:

  1. Selekter DISTINCT-værdier fra tabellen og bestil
  2. Selekter de TOP x rækker fra resultaterne i trin 1 og vis.

Hvis du selv vil prøve dette, så start med

SELECT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Og læg mærke til resultaterne. Hold øje med “Kim Ambercombie”. Læg mærke til, at der er tre poster for hendes navn.

Resultater sorteret efter Efternavn

Kør nu

SELECT DISTINCT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Og du vil se, at “Kim Ambercombine” kun vises én gang.

Uniqueliste sorteret efter Efternavn

Kør nu

SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Og du vil se, at den returnerer de første 10 unikke for- og efternavne som sorteret efter Efternavn.

Første 10 unikke rækker sorteret efter LastName

Hvis du undrer dig over, hvad der sker først, DISTINCT- eller TOP 10-operationen, så sammenlign resultaterne fra de to sidste forespørgsler.

Bemærk, at forespørgslen “DISTINCT TOP 10” omfatter de første 10 rækker fra forespørgslen fra “DISTINCT”-forespørgslen.

Deraf ved vi, at der først oprettes en DISTINCT-liste, og derefter returneres de 10 TOP 10-elementer.

Søgningsplan, der viser rækkefølgen af udførelsen

Du kan også bekræfte dette ved at vise søgeskemaet. Det gør du ved at vælge Query ->Inddrag faktisk forespørgselsplan i menuen, før du udfører forespørgslen.

Ikonet “Stream Aggregate” er for DISTINCT-operationen og “Top” for TOP 10-operationen.

Det kan virke lidt kontraintuitivt at se DISTINCT opført først i SELECT-erklæringen. Bare husk på, at SQL ikke nødvendigvis behandles i den rækkefølge, som et menneske ville læse det fra venstre til højre.

DISTINCT og TOP med SELECT-listeudtryk

Den anden del af Nans spørgsmål vedrørte, hvordan udtryk behandles med DISTINCT-operatoren.

Udtryk behandles på samme måde som kolonner med hensyn til DISTINCT og TOP. Lad os starte med en select-anvisning for at få fornavnet samt det fulde, som vi opretter ved at tilføje LastName til FirstName.

Og husk også, når du bruger ORDER BY, at ORDER BY-elementerne skal vises i select-listen, når du bruger Distinct. I betragtning af dette er jeg nødt til at ændre den erklæring, der blev præsenteret i det oprindelige spørgsmål:

SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName

Kører ikke, da LastName ikke er i SELECT-listen. Ja, det er en del af et udtryk i select-listen, men det er der ikke i sig selv. Det er gyldigt at bestille efter FullName.

Vi vil bruge denne bestilling i eksemplerne nedenfor.

Ordningen

SELECT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Returnerer 19972 rækker. Når vi tilføjer Distinct

SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Der returneres 19516 rækker. Endelig tilføjer vi Top 10 og returnerer de første 10 distinkte navnekombinationer.

SELECT DISTINCT TOP 10 FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName

Forsøg at køre disse forespørgsler på AdventureWork-databasen, og du kan selv se, at opførslen er den samme som den, vi finder, når vi udelukkende arbejder med kolonner.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.