Да предположим, че проектирате приложение за база данни на SQL Server за главен изпълнителен директор на компанията и трябва да покажете петия най-високоплатен служител в компанията.
Какво би направил? Едно решение е да напишете заявка като тази:
SELECT EmployeeName FROM Employees ORDER BY Salary DESC OFFSET 4 ROWS FETCH FIRST 1 ROWS ONLY;
Заявката по-горе изглежда тромава, особено ако трябва да класирате всички служители. В този случай едно решение е да изброите служителите по низходящ ред на заплатата и след това да вземете индекса на служителя като ранг. Нещата обаче се усложняват, ако множеството служители имат една и съща заплата. Как бихте ги класирали?
За щастие SQL Server идва с вградени функции за класиране, които могат да се използват за класиране на записи по различни начини. В тази статия ще представим функциите за класиране на SQL сървъри в подробности, илюстрирайки го с примерите.
Има четири различни типа функции за класиране в SQL Server:
- Ранг()
- Dense_Rank()
- Номер на ред()
- Ntile()
Важно е да се спомене, че всички функции за класиране в SQL сървър изискват клаузата ORDER BY.
Преди да разгледаме подробно всяка от функциите за класиране, първо, нека създадем фиктивни данни, които ще използваме в тази статия, за да обясним функцията за класиране. Изпълнете следния скрипт:
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')
В скрипта по-горе създаваме база данни на Showroom с една маса Car. Таблицата Car има пет атрибута:CarId, Име, Марка, Модел, Цена и Тип.
След това добавихме 12 фиктивни записа в таблицата Car.
Сега виждате всяка от функциите за класиране.
1. Функция за ранг
Функцията за ранг в SQL сървъра присвоява ранг на всеки запис, подреден от клаузата ORDER BY. Например, ако искате да видите петата най-скъпа кола в таблицата Car, можете да използвате функцията за ранг, както следва:
Use Showroom SELECT Name,Make,Model, Price, Type, RANK() OVER(ORDER BY Price DESC) as PriceRank FROM Car
В скрипта по-горе изберете Име, Марка, Модел, Цена, Тип и ранга на всяка кола, подредена по Цена, като колона „PriceRank“. Синтаксисът за функцията Rank е прост. Трябва да напишете функцията RANK, последвана от оператора OVER. Вътре в оператора OVER трябва да предадете клаузата ORDER BY, която сортира данните. Резултатът от скрипта по-горе изглежда така:
Можете да видите ранга за всяка кола. Важно е да се спомене, че ако има равенство между ранговете на два рекорда, следващата позиция в класирането се пропуска. Например, има връзка между запис 5 и 6 в изхода. И Parado, и Civic имат равни цени и следователно са класирани на 5. Следващият ранг обаче, по-специално ранг 6, е пропуснат и следващите две коли в списъка са класирани на 7, тъй като те също имат една и съща цена. След 7-ми ранг, ранг 8 се пропуска отново и следващият присвоен ранг е 9.
Можете да разделите данните на дялове и след това да приложите класиране към отделни дялове. В следващия скрипт има разделяне на записите по тип. Класираме колите във всеки дял.
SELECT Name,Make,Model, Price, Type, RANK() OVER(PARTITION BY Type ORDER BY Price DESC) as PriceRank FROM Car
Резултатът от скрипта по-горе изглежда така:
От изхода е видно, че записите са разделени по видове автомобили и рангът е присвоен локално вътре в дяла. Например, първите два записа принадлежат на дял „Хечбек“ и са класирани на 1 и 2. За следващия дял, т.е. „Седан“, рангът се нулира на 1.
2. Функция Dense_Rank
Функцията dense_rank е подобна на функцията за ранг. Въпреки това, в случай на dense_rank, ако има равенство между два записа по отношение на ранга, следващият ранг не се пропуска. Нека видим да го демонстрираме с примера. Изпълнете следния скрипт:
Use Showroom SELECT Name,Make,Model, Price, Type, DENSE_RANK() OVER(ORDER BY Price DESC) as DensePriceRank FROM Car
Отново можете да видите, че 5-ти и 6-ти запис имат една и съща стойност за Price и и на двата им е присвоен ранг 5. Въпреки това, за разлика от функцията за ранг, която е пропуснала следващия ранг, функцията dense_rank не пропуска следващия ранг, а ранга 6 е присвоен към следващия запис.
Подобно на функцията за ранг, функцията dense_rank също може да бъде приложена към разделянето по клауза. Вижте следния скрипт:
SELECT Name,Make,Model, Price, Type, DENSE_RANK() OVER(PARTITION BY Type ORDER BY Price DESC) as DensePriceRank FROM Car
Резултатът от скрипта по-горе изглежда така:
3. Функция номер_ред
Функцията row_number също така класира записите според условията, посочени от клаузата ORDER BY. Въпреки това, за разлика от функциите rank и dense_rank, функцията row_number не присвоява същия ранг, когато има дублиращи се стойности за колоната, определена от клаузата ORDER BY. Вижте следния скрипт:
SELECT Name,Make,Model, Price, Type, DENSE_RANK() OVER(PARTITION BY Type ORDER BY Price DESC) as DensePriceRank FROM Car
Резултатът от скрипта по-горе изглежда така:
От скрипта по-горе можете да видите, че и 5-ият, и 6-ият запис имат една и съща стойност за колона Цена, но рангът, присвоен им е различен.
По подобен начин функцията row_number може да се приложи към разделените данни. Вижте например следния скрипт.
SELECT Name,Make,Model, Price, Type, ROW_NUMBER() OVER(PARTITION BY Type ORDER BY Price DESC) AS PriceRankRow FROM Car
Резултатът от скрипта по-горе изглежда така:
4. NTILE функция
Функцията NTILE групира класирането. Да предположим, че имате 12 записа в таблица и искате да ги класирате в групи от по 4. Първите три записа ще имат ранг 1, следващите три записа ще имат ранг 2 и така нататък.
Нека да разгледаме пример за функцията NTILE.
Use Showroom SELECT Name,Make,Model, Price, Type, NTILE(4) OVER(ORDER BY Price DESC) as NtilePrice FROM Car
В горния скрипт предадохме 4 като параметър на функцията NTILE. Тъй като имаме 12 записа, ще видите общо 4 различни ранга, където 1 ранг ще бъде присвоен на три записа. Резултатът изглежда така:
Можете да видите, че първите три най-скъпи коли са класирани на 1, следващите три са на 2 и така нататък.
Функцията NTILE може да се приложи и към разделените данни. Вижте следния скрипт:
SELECT Name,Make,Model, Price, Type, NTILE(4) OVER(PARTITION BY Type ORDER BY Price DESC) as NtilePrice FROM Car
Заключение
Функциите за класиране в SQL Server се използват за класиране на данни по различни начини. В това четиво ние представихме различни видове функции за класиране с примерите. Функциите rank и dense_rank дават един и същ ранг на данните със същите стойности в клаузата ORDER BY, докато функцията row_number класира записа по нарастващ начин, дори ако има равенство.
В случай на липса на дублиращи се записи в посочената колона от клаузата ORDER BY функциите за ранг, dense_rank и row_number се държат по подобен начин.