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:

  1. Wybierz DISTINCT Values z tabeli i zamów
  2. 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.

Results sorted by LastName

Now run

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

And you’ll see that „Kim Ambercombine” is shown only once.

Lista unikalnych nazwisk posortowana według LastName

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.

Pierwsze 10 unikalnych wierszy uporządkowanych 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.

Plan zapytania pokazujący kolejność wykonywania

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.

.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.