Załóżmy, że projektujesz aplikację bazodanową SQL Server dla dyrektora generalnego firmy i musisz wskazać piątego najlepiej opłacanego pracownika w firmie.
Co byś zrobił? Jednym z rozwiązań jest napisanie takiego zapytania:
SELECT EmployeeName FROM Employees ORDER BY Salary DESC OFFSET 4 ROWS FETCH FIRST 1 ROWS ONLY;
Powyższe zapytanie wygląda na nieporęczne, szczególnie jeśli musisz uszeregować wszystkich pracowników. W takim przypadku jednym z rozwiązań jest utworzenie listy pracowników w porządku malejącym wynagrodzenia, a następnie przyjęcie indeksu pracownika jako rangi. Jednak sytuacja się komplikuje, jeśli wielu pracowników ma tę samą pensję. Jak byś je uszeregował?
Na szczęście SQL Server ma wbudowane funkcje rankingowe, które można wykorzystać do rankingu rekordów na różne sposoby. W tym artykule przedstawimy funkcje rankingu serwerów SQL szczegółowo ilustrując to na przykładach.
W SQL Server istnieją cztery różne typy funkcji rankingu:
- Rank()
- Gęsty_Rank()
- Numer wiersza()
- Ntile()
Należy wspomnieć, że wszystkie funkcje rankingowe na serwerze SQL wymagają klauzuli ORDER BY.
Zanim szczegółowo przyjrzymy się każdej z funkcji rankingu, najpierw utwórzmy dane fikcyjne, których będziemy używać w tym artykule, aby wyjaśnić funkcję rankingu. Wykonaj następujący skrypt:
CREATE DATABASE Showroom Use Showroom CREATE TABLE Car ( CarId int identity(1,1) primary key, Name varchar(100), Make varchar(100), Model int , Price int , Type varchar(20) ) insert into Car( Name, Make, Model , Price, Type) VALUES ('Corrolla','Toyota',2015, 20000,'Sedan'), ('Civic','Honda',2018, 25000,'Sedan'), ('Passo','Toyota',2012, 18000,'Hatchback'), ('Land Cruiser','Toyota',2017, 40000,'SUV'), ('Corrolla','Toyota',2011, 17000,'Sedan'), ('Vitz','Toyota',2014, 15000,'Hatchback'), ('Accord','Honda',2018, 28000,'Sedan'), ('7500','BMW',2015, 50000,'Sedan'), ('Parado','Toyota',2011, 25000,'SUV'), ('C200','Mercedez',2010, 26000,'Sedan'), ('Corrolla','Toyota',2014, 19000,'Sedan'), ('Civic','Honda',2015, 20000,'Sedan')
W powyższym skrypcie tworzymy bazę danych Showroom z jedną tabelą Car. Tabela samochodów ma pięć atrybutów:identyfikator samochodu, nazwa, marka, model, cena i typ.
Następnie dodaliśmy 12 fikcyjnych rekordów w tabeli Samochód.
Teraz widzisz każdą z funkcji rankingowych.
1. Funkcja rangowa
Funkcja rangi w serwerze SQL przypisuje rangę do każdego rekordu uporządkowanego według klauzuli ORDER BY. Na przykład, jeśli chcesz zobaczyć piąty najdroższy samochód w tabeli Samochód, możesz użyć funkcji rankingu w następujący sposób:
Use Showroom SELECT Name,Make,Model, Price, Type, RANK() OVER(ORDER BY Price DESC) as PriceRank FROM Car
W powyższym skrypcie wybierz nazwę, markę, model, cenę, typ i pozycję każdego samochodu zamówionego według ceny jako kolumnę „Ranking ceny”. Składnia funkcji Ranga jest prosta. Musisz napisać funkcję RANK, po której następuje operator OVER. Wewnątrz operatora OVER należy przekazać klauzulę ORDER BY, która sortuje dane. Wynik powyższego skryptu wygląda tak:
Możesz zobaczyć rangę dla każdego samochodu. Należy wspomnieć, że w przypadku remisu między dwoma rekordami w rankingu kolejna pozycja w rankingu jest pomijana. Na przykład istnieje remis między rekordem 5 i 6 w wynikach. Zarówno Parado, jak i Civic mają takie same ceny, a więc zajęły 5. miejsce. Jednak kolejna pozycja, w szczególności pozycja 6, została pominięta, a kolejne dwa samochody na liście zajęły 7. miejsce, ponieważ również mają tę samą cenę. Po 7 pozycji pozycja 8 jest ponownie pomijana, a następna przypisana pozycja to 9.
Możesz podzielić dane na partycje, a następnie zastosować ranking do poszczególnych partycji. W poniższym skrypcie istnieje podział rekordów według typu. Klasyfikujemy samochody wewnątrz każdej partycji.
SELECT Name,Make,Model, Price, Type, RANK() OVER(PARTITION BY Type ORDER BY Price DESC) as PriceRank FROM Car
Wynik powyższego skryptu wygląda tak:
Z danych wyjściowych wynika, że rekordy zostały podzielone według typów samochodów, a ranga została przypisana lokalnie wewnątrz partycji. Na przykład pierwsze dwa rekordy należą do partycji „Hatchback” i otrzymały rangę 1 i 2. Dla następnej partycji, tj. „Sedan”, ranga jest resetowana do 1.
2. Funkcja Gęsty_Rank
Funkcja gęsta_rank jest podobna do funkcji rangi. Jednak w przypadku gęstej_rangi, jeśli istnieje remis między dwoma rekordami pod względem rangi, następna pozycja nie jest pomijana. Zobaczmy, jak to zademonstrować na przykładzie. Wykonaj następujący skrypt:
Use Showroom SELECT Name,Make,Model, Price, Type, DENSE_RANK() OVER(ORDER BY Price DESC) as DensePriceRank FROM Car
Ponownie widać, że rekord 5 i 6 mają tę samą wartość dla ceny i oba mają przypisaną rangę 5. Jednak w przeciwieństwie do funkcji rank, która pomija kolejną pozycję, funkcja gęstości_rank nie pomija następnej pozycji, a pozycja 6 został przypisany do następnego rekordu.
Podobnie jak funkcja rank, funkcja gęsta_rank może być również zastosowana do klauzuli partition by. Spójrz na następujący skrypt:
SELECT Name,Make,Model, Price, Type, DENSE_RANK() OVER(PARTITION BY Type ORDER BY Price DESC) as DensePriceRank FROM Car
Wynik powyższego skryptu wygląda tak:
3. Funkcja numeru wiersza
Funkcja numer_wiersza również klasyfikuje rekordy zgodnie z warunkami określonymi w klauzuli ORDER BY. Jednak w przeciwieństwie do funkcji rank i density_rank funkcja row_number nie przypisuje tej samej rangi w przypadku zduplikowanych wartości dla kolumny określonej w klauzuli ORDER BY. Spójrz na następujący skrypt:
SELECT Name,Make,Model, Price, Type, DENSE_RANK() OVER(PARTITION BY Type ORDER BY Price DESC) as DensePriceRank FROM Car
Wynik powyższego skryptu wygląda tak:
Z powyższego skryptu widać, że zarówno 5, jak i 6 rekord mają tę samą wartość w kolumnie Cena, ale przypisana im ranga jest inna.
Podobnie funkcję row_number można zastosować do danych podzielonych na partycje. Spójrz na przykład na poniższy skrypt.
SELECT Name,Make,Model, Price, Type, ROW_NUMBER() OVER(PARTITION BY Type ORDER BY Price DESC) AS PriceRankRow FROM Car
Wynik powyższego skryptu wygląda tak:
4. Funkcja NTILE
Funkcja NTILE grupuje ranking. Załóżmy, że masz 12 rekordów w tabeli i chcesz je uszeregować w grupy po 4. Pierwsze trzy rekordy będą miały pozycję 1, kolejne trzy będą miały pozycję 2 i tak dalej.
Rzućmy okiem na przykład funkcji NTILE.
Use Showroom SELECT Name,Make,Model, Price, Type, NTILE(4) OVER(ORDER BY Price DESC) as NtilePrice FROM Car
W powyższym skrypcie przekazaliśmy 4 jako parametr do funkcji NTILE. Ponieważ mamy 12 rekordów, zobaczysz w sumie 4 różne rangi, gdzie 1 pozycja zostanie przypisana do trzech rekordów. Wynik wygląda tak:
Widać, że pierwsze trzy najdroższe samochody zajęły 1 miejsce, kolejne trzy zajęły 2 miejsce i tak dalej.
Funkcję NTILE można również zastosować do danych podzielonych na partycje. Spójrz na następujący skrypt:
SELECT Name,Make,Model, Price, Type, NTILE(4) OVER(PARTITION BY Type ORDER BY Price DESC) as NtilePrice FROM Car
Wniosek
Funkcje rankingowe w SQL Server służą do klasyfikowania danych na różne sposoby. W tej lekturze przedstawiliśmy na przykładach różne rodzaje funkcji rankingowych. Funkcje rank i density_rank nadają tę samą rangę danym o tych samych wartościach w klauzuli ORDER BY, podczas gdy funkcja row_number klasyfikuje rekord w sposób przyrostowy, nawet jeśli występuje remis.
W przypadku braku zduplikowanych rekordów w określonej kolumnie przez klauzulę ORDER BY funkcje rank, thick_rank i row_number zachowują się w podobny sposób.