TOP od tyłu (z końcowymi rekordami)

12-Wrz-2013

Trzeba uporządkować rekordy wg pewnej kolumny, w naszym przykładzie dajmy na to wg orderid. Spośród tych rekordów chcemy wybrać tylko 5 ostatnich. Ha nic w tym trudnego, wystarczy takie zapytanie:

SELECT TOP(5) orderid FROM Sales.Orders
ORDER BY ordered DESC

…tylko, że użytkownik chce zobaczyć te rekordy ułożone w kolejności rosnącej. Jeśli w zapytaniu zmienisz DESC na ASC to TOP(5) wybierze 5 rekordów z najniższym id, a nam chodziło o najwyższe…

Z pomocą przychodzi podzapytanie. Mianowicie z rekordów zwróconych w zapytaniu powyżej wybierzmy jeszcze raz tych 5 rekordów i ułóżmy je po prostu w innej kolejności:

SELECT orderid FROM
(SELECT TOP(5) orderid FROM Sales.Orders
ORDER BY orderid DESC) AS x
ORDER BY ordered ASC

Gotowe. Na dodatek działa dość wydajnie J Po prodtu zwrócone wcześniej rekordy zostały na nowo posortowane na kolejność ASC.

Inne rozwiązania okazały się nieco gorsze:

Wykorzystanie klauzuli OFFSET do polecenia ORDER BY (od SQL 2012). Pomysł jest prosty. Ułóżmy rekordy w kolejności prezentacji (czyli ASC), ale wyświetlmy tylko ostatnich 5. Żeby dowiedzieć się ile rekordów należy opuścić (instrukcja OFFSET) trzeba najpierw policzyć ile tych rekordów mamy i opuścić ilość minus pięć:

DECLARE @c  INT = (SELECT COUNT(*) FROM Sales.Orders)
SELECT orderid FROM Sales.Orders
ORDER BY ordered ASC OFFSET @c-5 ROWS

Kolejny pomysł wykorzystuje EXCEPT. Można wziąć rekordy ułożone w kolejności ASC , a następnie z tego zbioru odjąć (operacja na zbiorach) te rekordy, których nie chcemy pokazywać, czyli ilość minus pięć rekordów wg kolejności ASC:

DECLARE @c  INT = (SELECT COUNT(*) FROM Sales.Orders)
SELECT orderid FROM Sales.Orders
EXCEPT
SELECT TOP(@c – 5) ordered FROM Sales.Orders
ORDER BY orderId ASC

 Wydajnościowo te dwa rozwiązania wypadły gorzej niż pierwsze, zaprezentowane na początku.

Dodaj komentarz:

Autor: Rafał Kraik