SQL DISTINCT i TOP w tym samym zapytaniu
Ten artykuł jest zainspirowany serią pytań, które jeden z moich czytelników, Nan, wysłał mi ostatnio w związku z DISTINCT, TOP i ORDER BY.
Wszystkie przykłady do tej lekcji są oparte na Microsoft SQL Server Management Studio i bazie danych AdventureWorks2012. Możesz zacząć korzystać z tych darmowych narzędzi, używając mojego przewodnika Getting Started Using SQL Server.
How do the SQL Top and Distinct SELECT modifiers Work Together to Produce Results?
Tutaj jest pytanie, które Nan pierwotnie do mnie wysłał:
Jestem trochę zdezorientowany co do SELECT DISTINCT i SELECT. Na przykład,
SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName
Czy jest to patrzenie na odrębne pierwsze imiona? Odrębnych połączonych imion i nazwisk? Jak rozróżnić kolumny używane do oceny distinct i kolumny, które chcemy pokazać na wyjściu?
Co z
Select Distinct TOP 10 LastName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName
Pomyślałem, że każdy chciałby znać odpowiedź, więc stworzyłem wpis na blogu.
DISTINCT and TOP – Which is First?
Przyjrzyjrzyjmy się pierwszej instrukcji, której celem jest zwrócenie unikalnej listy imion i nazwisk.
SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName;
TOP 10 zwróci pierwsze dziesięć elementów z uporządkowanego zbioru, a DISTINCT usunie wszelkie duplikaty. Pytanie brzmi, co dzieje się najpierw?
- Czy tabela jest sortowana według LastName i pobierana jest pierwsza dziesiątka elementów, a następnie usuwane są duplikaty nazwisk?
- Czy też usuwane są duplikaty, a następnie elementy są sortowane i wyświetlana jest pierwsza dziesiątka elementów?
Zanim odpowiemy na to pytanie, pamiętajmy, że DISTINCT działa na wszystkich kolumnach i wyrażeniach w klauzuli SELECT. Tak więc, w tym przypadku, instrukcja zwróci różne wiersze dla FirstName i LastName.
Niestety nie ma bezpośredniego sposobu, aby użyć DISTINCT na jednym zestawie pól i wyświetlić inne. Po dodaniu kolumn do instrukcji SELECT stają się one pod wpływem operatora DISTINCT. Mówię bezpośredni, ponieważ możesz uzyskać odrębną listę, a następnie użyć INNER JOIN, aby wyciągnąć inne kolumny. Istnieją jednak niebezpieczeństwa, aby to zrobić, ponieważ połączenie może ponownie wprowadzić duplikaty.
Dodanie klauzuli TOP do DISTINCT jest interesujące. Nie byłem pewien, co się stanie, ale poeksperymentowałem trochę z bazą danych AdventureWorks i odkryłem, że kolejność przetwarzania idzie mniej więcej tak:
- Wybierz DISTINCT Values z tabeli i zamów
- Wybierz x wierszy TOP z wyników w kroku 1 i wyświetl.
Jeśli chcesz spróbować tego samemu, zacznij od
SELECT FirstName,
LastName
FROM Person.Person
ORDER BY LastName
I zauważ wyniki. Prześledź „Kim Ambercombie”. Zauważ, że istnieją trzy wpisy dla jej nazwiska.
Now run
SELECT DISTINCT FirstName,
LastName
FROM Person.Person
ORDER BY LastName
And you’ll see that „Kim Ambercombine” is shown only once.
Teraz uruchom
SELECT DISTINCT TOP 10 FirstName,
LastName
FROM Person.Person
ORDER BY LastName
I zobaczysz, że zwraca 10 pierwszych unikalnych imion i nazwisk posortowanych według LastName.
Jeśli zastanawiasz się, co dzieje się najpierw, operacje DISTINCT czy TOP 10, to porównaj wyniki z dwóch ostatnich zapytań.
Zauważ, że zapytanie „DISTINCT TOP 10” zawiera pierwsze 10 wierszy z zapytania „DISTINCT”.
Z tego wiemy, że najpierw tworzona jest lista DISTINCT, a następnie zwracane jest TOP 10 elementów.
Można to również potwierdzić pokazując plan zapytania. Aby to zrobić, wybierz Query -> Include Actual Query Plan z menu przed wykonaniem zapytania.
Ikona „Stream Aggregate” jest dla operacji DISTINCT, a „Top” dla TOP 10.
Może wydawać się nieco sprzeczne z intuicją, aby zobaczyć DISTINCT wymienione jako pierwsze w instrukcji SELECT. Należy pamiętać, że SQL niekoniecznie jest przetwarzany w kolejności, w jakiej człowiek czyta go od lewej do prawej.
DISTINCT i TOP z wyrażeniami listy SELECT
Druga część pytania Nana dotyczyła tego, jak wyrażenia są traktowane z operatorem DISTINCT.
Wyrażenia są traktowane tak samo jak kolumny w odniesieniu do DISTINCT i TOP. Zacznijmy od instrukcji select, aby uzyskać pierwsze imię, jak również pełne, które tworzymy przez dołączenie LastName do FirstName.
Pamiętajmy również, gdy używamy ORDER BY, że elementy ORDER BY muszą pojawić się na liście wyboru, gdy używamy Distinct. Biorąc to pod uwagę, muszę zmodyfikować oświadczenie przedstawione w oryginalnym pytaniu:
SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY LastName
Won’t run since LastName isn’t in the SELECT list. Tak, jest to część wyrażenia na liście select, ale nie ma jej tam samodzielnie. Ważne jest, aby zamawiać według FullName.
Użyjemy tego zamawiania w poniższych przykładach.
Oświadczenie
SELECT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName
Zwraca 19972 wiersze. Gdy dodamy Distinct
SELECT DISTINCT FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName
Wówczas zwróconych zostanie 19516 wierszy. Na koniec dodając Top 10, zwracamy pierwsze 10 różnych kombinacji nazwisk.
SELECT DISTINCT TOP 10 FirstName,
FirstName + ' ' + LastName AS FullName
FROM Person.Person
ORDER BY FirstName + ' ' + LastName
Spróbuj uruchomić te zapytania na bazie danych AdventureWork i sam zobaczysz, że zachowanie jest takie samo jak przy pracy wyłącznie z kolumnami.
.