SQL DISTINCT și TOP în aceeași interogare

Acest articol este inspirat de o serie de întrebări pe care unul dintre cititorii mei, Nan, mi le-a trimis recent cu privire la DISTINCT, TOP și ORDER BY.

Toate exemplele pentru această lecție se bazează pe Microsoft SQL Server Management Studio și pe baza de date AdventureWorks2012. Puteți începe să utilizați aceste instrumente gratuite cu ajutorul Ghidului meu Getting Started Using SQL Server.

Cum lucrează împreună modificatorii SQL Top și Distinct SELECT pentru a produce rezultate?

Iată întrebarea pe care mi-a trimis-o inițial Nan:

Sunt puțin confuz în legătură cu SELECT DISTINCT și SELECT. De exemplu,

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

Acesta caută prenume distincte? Nume și prenume distincte combinate? Cum facem distincția între coloanele utilizate pentru evaluarea distinctă și coloanele pe care vrem doar să le arătăm în ieșire?

Ce zici de

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

M-am gândit că toată lumea ar dori să știe răspunsul, așa că am creat o postare pe blog.

DISTINCT și TOP – Care este primul?

Să ne uităm la prima instrucțiune al cărei scop este de a returna o listă unică de nume și prenume.

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

TOP 10 va returna primele zece elemente din setul ordonat, iar DISTINCT va elimina orice duplicate. Întrebarea este ce se întâmplă mai întâi?

  • Se sortează tabelul după LastName și se iau primele zece elemente, apoi se elimină numele duplicat?
  • O se elimină dublurile, apoi se sortează elementele și se afișează primele zece elemente?

Înainte de a răspunde la această întrebare, rețineți că DISTINCT operează pe toate coloanele și expresiile din clauza SELECT. Deci, în acest caz, instrucțiunea va returna rânduri distincte pentru FirstName și LastName.

Din păcate, nu există o modalitate directă de a utiliza DISTINCT pe un set de câmpuri și de a afișa celelalte. Odată ce adăugați coloane la instrucțiunea SELECT, acestea devin sub influența operatorului DISTINCT. Spun direct, deoarece ați putea obține o listă distinctă și apoi să folosiți un INNER JOIN pentru a atrage alte coloane. Există totuși pericole în a face acest lucru, deoarece join-ul poate reintroduce duplicate.

Aducerea unei clauze TOP la DISTINCT este interesantă. Nu eram sigur ce se va întâmpla, dar am făcut câteva experimente cu baza de date AdventureWorks și am descoperit că ordinea de procesare este cam așa:

  1. Selectați valorile DISTINCT din tabel și ordonați
  2. Selectați TOP x rânduri din rezultatele de la pasul 1 și afișați-le.

Dacă doriți să încercați acest lucru singur, începeți cu

SELECT FirstName,
LastName
FROM Person.Person
ORDER BY LastName

Și observați rezultatele. Țineți cont de „Kim Ambercombie”. Observați cum există trei intrări pentru numele ei.

Rezultate sortate după numele de familie

Acum rulați

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

Și veți vedea că „Kim Ambercombine” apare o singură dată.

Listă unică ordonată după LastName

Apoi rulați

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

Și veți vedea că returnează primele 10 nume și prenume unice, ordonate după LastName.

Primele 10 rânduri unice ordonate după LastName

Dacă vă întrebați ce se întâmplă mai întâi, operațiile DISTINCT sau TOP 10, atunci comparați rezultatele ultimelor două interogări.

Observați că interogarea „DISTINCT TOP 10” include primele 10 rânduri din interogarea din interogarea „DISTINCT”.

Din acest lucru știm că mai întâi se creează o listă DISTINCT, iar apoi se returnează TOP 10 elemente.

Planul de interogare care arată ordinea de execuție

Puteți confirma acest lucru și prin afișarea planului de interogare. Pentru a face acest lucru, selectați Query -> Include Actual Query Plan din meniu înainte de a executa interogarea.

Icoana „Stream Aggregate” este pentru operația DISTINCT, iar „Top” pentru cea TOP 10.

Poate părea oarecum contraintuitiv să vedeți DISTINCT listat primul în cadrul instrucțiunii SELECT. Rețineți că SQL nu este neapărat procesat în ordinea în care un om l-ar citi de la stânga la dreapta.

DISTINCT și TOP cu expresiile din lista SELECT

A doua parte a întrebării lui Nan se referea la modul în care sunt tratate expresiile cu operatorul DISTINCT.

Expresiile sunt tratate la fel ca și coloana în ceea ce privește DISTINCT și TOP. Să începem cu o instrucțiune select pentru a obține primul nume, precum și numele complet, pe care îl creăm prin adăugarea lui LastName la FirstName.

De asemenea, rețineți, atunci când folosiți ORDER BY, că elementele ORDER BY trebuie să apară în lista select atunci când folosiți Distinct. Având în vedere acest lucru, trebuie să modific declarația prezentată în întrebarea inițială:

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

Nu se va executa deoarece LastName nu se află în lista SELECT. Da, face parte dintr-o expresie din lista de selecție, dar nu este acolo de una singură. Este valabilă ordonarea după FullName.

Vom folosi această ordonare în exemplele de mai jos.

Executarea

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

Returnează 19972 de rânduri. Când adăugăm Distinct

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

Atunci sunt returnate 19516 rânduri. În cele din urmă, adăugând Top 10, se returnează primele 10 combinații distincte de nume.

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

Încercați să rulați aceste interogări pe baza de date AdventureWork și veți vedea cu ochii voștri că comportamentul este același cu cel pe care îl găsim atunci când lucrăm exclusiv cu coloane.

.

Lasă un răspuns

Adresa ta de email nu va fi publicată.