В тази статия ще проучим кога и как да използваме SQL клаузата PARTITION BY и ще я сравним с използването на клаузата GROUP BY.
Разбиране на функцията Window
Потребителите на база данни използват агрегатни функции като MAX(), MIN(), AVERAGE() и COUNT() за извършване на анализ на данни. Тези функции работят върху цяла таблица и връщат единични агрегирани данни с помощта на клаузата GROUP BY. Понякога изискваме обобщени стойности за малък набор от редове. В този случай функцията Window, комбинирана с функцията за обобщаване, помага за постигане на желания резултат. Функцията Window използва клаузата OVER() и може да включва следните функции:
- Разделяне по: Това разделя редовете или резултата от заявката на малки дялове.
- Поръчайте по: Това подрежда редовете във възходящ или низходящ ред за прозореца на дяла. Редът по подразбиране е възходящ.
- Ред или диапазон: Можете допълнително да ограничите редовете в дял, като посочите началната и крайната точка.
В тази статия ще се съсредоточим върху изследването на клаузата на SQL PARTITION BY.
Подготвяне на примерни данни
Да предположим, че имаме таблица [SalesLT].[Orders], която съхранява подробности за поръчката на клиента. Има колона [Град], която посочва града на клиента, където е направена поръчката.
CREATE TABLE [SalesLT].[Orders] ( orderid INT, orderdate DATE, customerName VARCHAR(100), City VARCHAR(50), amount MONEY ) INSERT INTO [SalesLT].[Orders] SELECT 1,'01/01/2021','Mohan Gupta','Alwar',10000 UNION ALL SELECT 2,'02/04/2021','Lucky Ali','Kota',20000 UNION ALL SELECT 3,'03/02/2021','Raj Kumar','Jaipur',5000 UNION ALL SELECT 4,'04/02/2021','Jyoti Kumari','Jaipur',15000 UNION ALL SELECT 5,'05/03/2021','Rahul Gupta','Jaipur',7000 UNION ALL SELECT 6,'06/04/2021','Mohan Kumar','Alwar',25000 UNION ALL SELECT 7,'07/02/2021','Kashish Agarwal','Alwar',15000 UNION ALL SELECT 8,'08/03/2021','Nagar Singh','Kota',2000 UNION ALL SELECT 9,'09/04/2021','Anil KG','Alwar',1000 Go
Да кажем, че искаме да знаем общата стойност на поръчките по местоположение (град). За тази цел използваме функциите SUM() и GROUP BY, както е показано по-долу.
SELECT City AS CustomerCity ,sum(amount) AS totalamount FROM [SalesLT].[Orders] GROUP BY city ORDER BY city
В резултатния набор не можем да използваме неагрегираните колони в оператора SELECT. Например, не можем да покажем [CustomerName] в изхода, защото не е включено в клаузата GROUP BY.
SQL Server дава следното съобщение за грешка, ако се опитате да използвате неагрегираната колона в списъка с колони.
SELECT City AS CustomerCity, CustomerName,amount, SUM(amount) OVER(PARTITION BY city) TotalOrderAmount FROM [SalesLT].[Orders]
Както е показано по-долу, клаузата PARTITION BY създава по-малък прозорец (набор от редове с данни), извършва агрегирането и го показва. Можете също да видите неагрегирани колони в този изход.
По същия начин можете да използвате функциите AVG(), MIN(), MAX(), за да изчислите средната, минималната и максималната сума от редовете в прозорец.
SELECT City AS CustomerCity, CustomerName,amount, SUM(amount) OVER(PARTITION BY city) TotalOrderAmount, Avg(amount) OVER(PARTITION BY city) AvgOrderAmount, Min(amount) OVER(PARTITION BY city) MinOrderAmount, MAX(amount) OVER(PARTITION BY city) MaxOrderAmount FROM [SalesLT].[Orders]
Използване на клаузата на SQL PARTITION BY с функцията ROW_NUMBER()
Преди това получавахме обобщените стойности в прозорец, използвайки клаузата PARTITION BY. Да предположим, че вместо общата сума изискваме кумулативната сума в дял.
Кумулативната сума работи по следните начини.
Ред | Общо с натрупване |
1 | Ранг 1+ 2 |
2 | Ранг 2+3 |
3 | Ранг 3+4 |
Рангът на реда се изчислява с помощта на функцията ROW_NUMBER(). Нека първо използваме тази функция и да видим редовете на редовете.
- Функцията ROW_NUMBER() използва клаузата OVER и PARTITION BY и сортира резултатите във възходящ или низходящ ред. Започва да подрежда редовете от 1 според реда на сортиране.
SELECT City AS CustomerCity, CustomerName,amount, ROW_NUMBER() OVER(PARTITION BY city ORDER BY amount DESC) AS [Row Number] FROM [SalesLT].[Orders]
Например, в града [Alwar], редът с най-висока сума (25000,00) е в ред 1. Както е показано по-долу, той подрежда редовете в прозореца, определен от клаузата PARTITION BY. Например имаме три различни града [Алвар], [Джайпур] и [Кота] и всеки прозорец (град) получава своите редове.
За да изчислим кумулативната сума, използваме следните аргументи.
- ТЕКУЩ РЕД:Посочва началната и крайната точка в посочения диапазон.
- 1 следното:Посочва броя на редовете (1), които следват от текущия ред.
SELECT City AS CustomerCity, CustomerName,amount, ROW_NUMBER() OVER(PARTITION BY city ORDER BY amount DESC) AS [Row Number], SUM(amount) OVER(PARTITION BY city ORDER BY amount DESC ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) AS CumulativeSUM FROM [SalesLT].[Orders]
Следното изображение показва, че получавате кумулативен сбор вместо обща сума в прозорец, определен от клаузата PARTITION BY.
Ако използваме РЕДОВЕ НЕОГРАНИЧЕНИ ПРЕДШЕСТВА в SQL PARTITION BY клаузата изчислява кумулативната сума по следния начин. Той използва текущите редове заедно с редовете с най-високи стойности в посочения прозорец.
Ред | Общо с натрупване |
1 | Ранг 1 |
2 | Ранг 1+2 |
3 | Ранг 1+2+3 |
SELECT City AS CustomerCity, CustomerName,amount, ROW_NUMBER() OVER(PARTITION BY city ORDER BY amount DESC) AS [Row Number], SUM(amount) OVER(PARTITION BY city ORDER BY amount DESC ROWS UNBOUNDED PRECEDING) AS CumulativeSUM FROM [SalesLT].[Orders]
Сравняване на клаузата GROUP BY и SQL PARTITION BY
ГРУПА ПО | РАЗДЕЛЯНЕ ПО |
Връща един ред на група след изчисляване на обобщените стойности. | Връща всички редове от оператора SELECT заедно с допълнителни колони с обобщени стойности. |
Не можем да използваме неагрегираната колона в израза SELECT. | Можем да използваме задължителни колони в израза SELECT и той не създава никакви грешки за неагрегираната колона. |
Изисква използване на клаузата HAVING за филтриране на записи от оператора SELECT. | Функцията PARTITION може да има допълнителни предикати в клаузата WHERE освен колоните, използвани в израза SELECT. |
ГРУПАТА BY се използва в обикновени агрегати. | PARTITION BY се използва в агрегати с прозорец. |
Не можем да го използваме за изчисляване на номера на редове или техния ранг. | Може да изчислява номера на редове и техните рангове в по-малкия прозорец. |
Предлага се за употреба
Препоръчително е да използвате клаузата на SQL PARTITION BY, докато работите с множество групи данни за агрегираните стойности в отделната група. По същия начин може да се използва за преглед на оригинални редове с допълнителна колона с обобщени стойности.