SQL DISTINCT en TOP in dezelfde query

Dit artikel is geïnspireerd op een reeks vragen die een van mijn lezers, Nan, me onlangs heeft gestuurd met betrekking tot DISTINCT, TOP en ORDER BY.

Alle voorbeelden voor deze les zijn gebaseerd op Microsoft SQL Server Management Studio en de AdventureWorks2012 database. U kunt aan de slag met deze gratis tools met behulp van mijn Gids Aan de slag met SQL Server.

Hoe werken de SQL Top en Distinct SELECT modifiers samen om resultaten te produceren?

Hier is de vraag die Nan me oorspronkelijk stuurde:

Ik ben een beetje in de war over SELECT DISTINCT en SELECT. Bijvoorbeeld,

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

Is dit op zoek naar verschillende voornamen? Onderscheiden gecombineerde voor- en achternamen? Hoe maken we onderscheid tussen de kolommen die voor de afzonderlijke evaluatie worden gebruikt en de kolommen die we alleen in de uitvoer willen laten zien?

En

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

Ik dacht dat iedereen het antwoord wel zou willen weten, dus heb ik een blogpost gemaakt.

DISTINCT en TOP – Welke is eerst?

Laten we eens kijken naar het eerste statement dat als doel heeft een unieke lijst van voor- en achternamen terug te geven.

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

TOP 10 zal de eerste tien items van de geordende set teruggeven, en DISTINCT zal eventuele duplicaten verwijderen. De vraag is nu wat er eerst gebeurt?

  • Wordt de tabel gesorteerd op achternaam en worden de eerste tien items genomen, waarna de dubbele namen worden verwijderd?
  • Of worden de dubbele items verwijderd, waarna de items worden gesorteerd en de eerste tien worden weergegeven?

Voordat we deze vraag beantwoorden, moeten we bedenken dat DISTINCT werkt op alle kolommen en uitdrukkingen in de SELECT-clausule. Dus, in dit geval, zal het statement verschillende rijen voor FirstName en LastName teruggeven.

Er is helaas geen directe manier om DISTINCT op een set velden te gebruiken en andere weer te geven. Zodra je kolommen aan het SELECT statement toevoegt, komen ze onder invloed van de DISTINCT operator te staan. Ik zeg direct, want je zou een afzonderlijke lijst kunnen krijgen, en dan een INNER JOIN gebruiken om andere kolommen op te halen. Er zijn echter gevaren aan verbonden, omdat de join duplicaten kan herintroduceren.

Het toevoegen van een TOP-clausule aan DISTINCT is interessant. Ik wist niet zeker wat er zou gebeuren, maar ik heb wat geëxperimenteerd met de AdventureWorks database en ontdekte dat de volgorde van verwerking ongeveer zo gaat:

  1. Selecteer DISTINCT Waarden uit Tabel en rangschik
  2. Selecteer de TOP x rijen uit de resultaten in stap 1 en toon.

Als je dit zelf wilt proberen, begin dan met

SELECT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

En let op de resultaten. Hou “Kim Ambercombie” in de gaten. Merk op dat er drie vermeldingen zijn voor haar naam.

Resultaten gesorteerd op Achternaam

Nu uitvoeren

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

En u zult zien dat “Kim Ambercombine” slechts één keer wordt weergegeven.

Unieke lijst gesorteerd op achternaam

Uitvoeren

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

En u zult zien dat de eerste 10 unieke voor- en achternamen worden weergegeven, gesorteerd op achternaam.

De eerste 10 unieke rijen gesorteerd op achternaam

Als u zich afvraagt wat er eerst gebeurt, de DISTINCT- of TOP 10-bewerkingen, vergelijk dan de resultaten van de laatste twee query’s.

Merk op dat de query “DISTINCT TOP 10” de eerste 10 rijen uit de query van de “DISTINCT”-query bevat.

Daaruit weten we dat er eerst een DISTINCT-lijst wordt gemaakt en dat vervolgens de TOP 10 items worden teruggegeven.

Query plan showing order of execution

U kunt dit ook bevestigen door het query plan te tonen. Selecteer hiervoor Query -> Include Actual Query Plan uit het menu voordat u de query uitvoert.

Het pictogram “Stream Aggregate” is voor de DISTINCT-bewerking en “Top” voor de TOP 10-bewerking.

Het lijkt misschien een beetje tegenstrijdig om DISTINCT als eerste in de SELECT-opdracht te zien staan. Houd er rekening mee dat SQL niet noodzakelijkerwijs wordt verwerkt in de volgorde waarin een mens het van links naar rechts zou lezen.

DISTINCT en TOP met SELECT list Expressions

Het tweede deel van Nan’s vraag had betrekking op hoe expressies worden behandeld met de DISTINCT operator.

Expressies worden hetzelfde behandeld als kolommen met betrekking tot DISTINCT en TOP. Laten we beginnen met een select statement om zowel de voornaam als de volledige te krijgen, die we maken door LastName toe te voegen aan FirstName.

Ook moet u er bij het gebruik van ORDER BY rekening mee houden dat de ORDER BY-items in de select-lijst moeten voorkomen als u Distinct gebruikt. Gegeven dit moet ik het statement uit de oorspronkelijke vraag aanpassen:

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

Wordt niet uitgevoerd omdat LastName niet in de SELECT lijst staat. Ja, het is onderdeel van een expressie in de select list, maar het is er niet op zichzelf. Het is geldig om te ordenen op Volledige naam.

We zullen deze ordening gebruiken in de voorbeelden hieronder.

Het statement

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

Ret retourneert 19972 rijen. Wanneer we Distinct

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

toevoegen, dan worden 19516 rijen teruggegeven. Tenslotte geeft het toevoegen van Top 10, de eerste 10 verschillende naamcombinaties.

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

Probeer deze query’s uit te voeren op de database van AdventureWork en u ziet zelf dat het gedrag hetzelfde is als wanneer we uitsluitend met kolommen werken.

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.