|
Execute the following
Microsoft SQL Server T-SQL scripts in Management Studio Query Editor to demonstrate how to use over partition by with ranking and aggregate window functions.
-- SQL over partiton by - QUICK SYNTAX - row_number over partition by - OVER clause
-- Find TOP selling salesstaff by city -- RANK() is used for ranking salesstaff
USE AdventureWorks2008;
WITH cteTopSalesStaffByCity
AS (SELECT p.FirstName + ' ' + p.LastName AS SalesStaff,
RANK()
OVER(PARTITION BY City ORDER BY SalesYTD DESC) AS RankNo
,
'$' + convert(VARCHAR,sp.SalesYTD,1) AS SalesYTD,
a.City,
a.PostalCode
FROM Sales.SalesPerson sp
INNER JOIN Person.Person p
ON sp.BusinessEntityID = p.BusinessEntityID
INNER JOIN Person.Address a
ON a.AddressID = p.BusinessEntityID
WHERE TerritoryID IS NOT NULL)
SELECT *
FROM cteTopSalesStaffByCity
WHERE RankNo = 1
ORDER BY City
GO
/*
SalesStaff RankNo SalesYTD City PostalCode
Linda Mitchell 1 $5,200,475.23 Issaquah 98027
Jae Pak 1 $5,015,682.38 Renton 98055
*/ ------------ -- Calculate aggregates over partition by PurchaseOrderID ------------ USE AdventureWorks; GO -- SQL Server over partition by - using partition by with aggregate functions -- SQL Server windowing functions - partition by sql server - t sql partition by SELECT PO = PurchaseOrderID, ProductID, OrderQty, SUM(OrderQty) OVER(PARTITION BY PurchaseOrderID ) AS 'TOTAL', AVG(OrderQty) OVER(PARTITION BY PurchaseOrderID ) AS 'Avg', COUNT(OrderQty) OVER(PARTITION BY PurchaseOrderID ) AS 'Count', MIN(OrderQty) OVER(PARTITION BY PurchaseOrderID ) AS 'Min', MAX(OrderQty) OVER(PARTITION BY PurchaseOrderID ) AS 'Max' FROM Purchasing.PurchaseOrderDetail WHERE PurchaseOrderID BETWEEN 10 AND 20 ORDER BY PurchaseOrderID, ProductID;
GO /* Partial results PO ProductID OrderQty TOTAL Avg Count Min Max 10 320 3 66 22 3 3 60 10 321 3 66 22 3 3 60 10 322 60 66 22 3 3 60 11 438 3 12 3 4 3 3 11 439 3 12 3 4 3 3 11 440 3 12 3 4 3 3 11 441 3 12 3 4 3 3
*/ ------------ -- SQL generate sequence number for partitioned data ------------ -- SQL Server row_number - using partition by with row_number() -- SQL over partition by order by - t sql ranking functions -- SQL Server COUNT aggregate function over partition by -- MSSQL windowing functions USE AdventureWorks; SELECT PO = PurchaseOrderID, VendorID, ShipDate = convert(VARCHAR,ShipDate,111), DailyPOCount = COUNT(*) OVER(PARTITION BY convert(VARCHAR,ShipDate,111) ), SeqNo = Row_Number() OVER(PARTITION BY convert(VARCHAR,ShipDate,111) ORDER BY PurchaseOrderID) FROM Purchasing.PurchaseOrderHeader WHERE YEAR(OrderDate) = 2003 AND MONTH(OrderDate) = 5 ORDER BY PurchaseOrderID GO /* Partial results PO VendorID ShipDate DailyPOCount SeqNo 297 3 2003/05/16 4 1 298 54 2003/05/16 4 2 299 104 2003/05/16 4 3 300 25 2003/05/16 4 4 301 90 2003/05/23 4 1 302 33 2003/05/23 4 2 303 41 2003/05/23 4 3 304 55 2003/05/23 4 4 305 70 2003/06/04 16 1 306 94 2003/06/04 16 2 307 15 2003/06/04 16 3 308 62 2003/06/04 16 4 309 98 2003/06/04 16 5 310 72 2003/06/04 16 6
*/
------------ -- SQL ranking functions over SalesOrderID by OrderQty ------------ -- SQL Server row_number - using the OVER clause with ranking functions -- SQL over partition by SalesOrderID - sql server windowing functions SELECT sod.SalesOrderID AS SO, OrderQty, ROW_NUMBER() OVER(PARTITION BY sod.SalesOrderID ORDER BY OrderQty DESC) AS [SeqNo], RANK() OVER(PARTITION BY sod.SalesOrderID ORDER BY OrderQty DESC) AS [Rank], DENSE_RANK() OVER(PARTITION BY sod.SalesOrderID ORDER BY OrderQty DESC) AS [DenseRank] FROM AdventureWorks.Sales.SalesOrderDetail sod INNER JOIN AdventureWorks.Sales.SalesOrderHeader soh ON soh.SalesOrderID = sod.SalesOrderID WHERE OrderDate = '2004-02-01' AND OrderQty > 1 ORDER BY SalesOrderID, SeqNo GO /* Partial results SO OrderQty SeqNo Rank DenseRank 63293 6 1 1 1 63293 4 2 2 2 63293 3 3 3 3 63293 3 4 3 3 63293 3 5 3 3 63293 3 6 3 3 63293 2 7 7 4 */
------------ -- SQL calculate minimum and maximum salaries by department ------------ -- SQL over partition by - aggregate functions: MIN, MAX USE AdventureWorks; WITH cteLastRaiseDate(EmployeeID,LastChangeDate) AS (SELECT EmployeeID, MAX(RateChangeDate) FROM HumanResources.EmployeePayHistory GROUP BY EmployeeID), ctePayRate(EmployeeID,Rate,Department) AS (SELECT eph.EmployeeID, eph.Rate, d.Name FROM HumanResources.EmployeePayHistory eph INNER JOIN cteLastRaiseDate lrd ON eph.EmployeeID = lrd.EmployeeID AND eph.RateChangeDate = lrd.LastChangeDate INNER JOIN HumanResources.EmployeeDepartmentHistory edh ON eph.EmployeeID = edh.EmployeeID INNER JOIN HumanResources.Department d ON edh.DepartmentID = d.DepartmentID WHERE edh.EndDate IS NULL) SELECT DISTINCT Department, MaxSalary = MAX(Rate) OVER(PARTITION BY Department ), MinSalary = MIN(Rate) OVER(PARTITION BY Department ) FROM ctePayRate ORDER BY Department GO /* Results Department MaxSalary MinSalary Document Control 17.7885 10.25 Engineering 63.4615 32.6923 Executive 125.50 60.0962 Facilities and Maintenance 24.0385 9.25 Finance 43.2692 13.4615 Human Resources 27.1394 13.9423 Information Services 50.4808 27.4038 Marketing 37.50 13.4615 Production 84.1346 9.50 Production Control 24.5192 16.00 Purchasing 30.00 12.75 Quality Assurance 28.8462 10.5769 Research and Development 50.4808 40.8654 Sales 72.1154 23.0769 Shipping and Receiving 19.2308 9.00 Tool Design 29.8462 25.00 */ ------------ -- SQL calculate aggregates by SalesOrderID ------------ -- SQL over partition by USE AdventureWorks; GO SELECT DISTINCT d.SalesOrderID, [Total Quantity] = SUM(OrderQty) OVER(PARTITION BY d.SalesOrderID ), [Average Quantity] = convert(VARCHAR,convert(MONEY,AVG(1.0 * OrderQty) OVER(PARTITION BY d.SalesOrderID ), 1)), [Total Order Count] = COUNT(OrderQty) OVER(PARTITION BY d.SalesOrderID ), [Minimum Order Count] = MIN(OrderQty) OVER(PARTITION BY d.SalesOrderID ), [Maximum Order Count] = MAX(OrderQty) OVER(PARTITION BY d.SalesOrderID ), [Average Amount] = convert(VARCHAR,convert(MONEY,AVG(LineTotal) OVER(PARTITION BY d.SalesOrderID ), 1)), [Total Amount] = convert(VARCHAR,convert(MONEY,SUM(LineTotal) OVER(PARTITION BY d.SalesOrderID ), 1)) FROM Sales.SalesOrderDetail d INNER JOIN Sales.SalesOrderHeader h ON h.SalesOrderID = d.SalesOrderID INNER JOIN Production.Product p ON d.ProductID = p.ProductID WHERE CustomerID = 100 ORDER BY SalesOrderID GO /* Partial results SalesOrderID Total Quantity Average Quantity Total Order Count 51818 81 2.61 31 57188 68 2.19 31 63290 68 2.96 23 69560 79 2.63 30 */ ------------ -- SQL calculate daily average traffic batch size ------------ -- SQL over partition by dates USE tempdb GO CREATE TABLE TollgateVehicleTraffic ( DateOfTollCollection DATETIME NOT NULL, Tolls INT NOT NULL); GO -- Populate table with daily batches INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 10,1260); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 9,2160); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 8,2265); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 7,1625); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 6,1550); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 5,1590); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 4,1200); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 4,2200); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 3,2150); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 2,2265); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 3,1465); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 1,1550); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 10,160); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 10,260); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 9,260); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 8,265); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 7,125); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 6,150); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 5,160); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 5,260); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 4,265); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 4,125); INSERT INTO TollgateVehicleTraffic VALUES (getdate() - 4,150); GO SELECT * FROM TollgateVehicleTraffic ORDER BY DateOfTollCollection; GO /* Partial results DateOfTollCollection Tolls 2009-02-11 19:53:55.873 1260 2009-02-11 19:53:55.890 160 2009-02-11 19:53:55.890 260 2009-02-12 19:53:55.873 2160 2009-02-12 19:53:55.890 260 2009-02-13 19:53:55.890 265 2009-02-13 19:53:55.890 2265 */ SELECT DateOfTollCollection = convert(CHAR(10),DateOfTollCollection,112), Tolls, FLOOR(AVG(Tolls) OVER()) AS AvgVehicleTrafficBatchSize FROM TollgateVehicleTraffic ORDER BY convert(CHAR(10),DateOfTollCollection,112); GO /* Partial results DateOfTollCollection Tolls AvgVehicleTrafficBatchSize 20090211 1260 1020 20090211 160 1020 20090211 260 1020 */ -- SQL over partition by - AVG aggregate function SELECT DISTINCT DateOfTollCollection = convert(CHAR(10),DateOfTollCollection,112), FLOOR(AVG(Tolls) OVER(PARTITION BY convert(CHAR(10),DateOfTollCollection,112) )) AS AvgDailyVehicleTrafficBatchSize FROM TollgateVehicleTraffic ORDER BY convert(CHAR(10),DateOfTollCollection,112); GO /* Results DateOfTollCollection AvgDailyVehicleTrafficBatchSize 20090211 560 20090212 1210 20090213 1265 20090214 875 20090215 850 20090216 670 20090217 788 20090218 1807 20090219 2265 20090220 1550 */ -- Cleanup DROP TABLE TollgateVehicleTraffic
GO |