Saturday, July 23, 2011

Using GROUPING and the WITH ROLLUP operator to create sub totals


 There are many occasions where you want to have subtotals appear on your query results, and using the GROUPING function along with the ROLLUP or CUBE operator I have found it to be an excellent way to accomplish that. This is especially useful when trying to export your results in a Text or CSV/Excel file, without having to rely on a reporting tool or keep variables for running totals in your program. Let’s take a look at a typical query using SUM to totals products sold and sales for a sample store.

SELECT pc.Name                      AS ProductName,
  p.Color                           AS ProductColor,
  SUM(sod.OrderQty)                 AS OrderQty,
  SUM(sod.orderqty * sod.UnitPrice) AS Sales
FROM Sales.SalesOrderDetail sod,
  Production.Product p,
  Production.ProductCategory pc
WHERE sod.ProductID             = p.ProductID
  AND p.ProductSubcategoryID    = pc.ProductCategoryID
GROUP BY pc.name, p.Color
ORDER BY pc.name, p.Color
 Output:
ProductNameProductColorOrderQtySales
BikesSilver1327117093187
BikesBlack1505019529109
ClothingYellow62956119206
ClothingBlue84568425868
ComponentsYellow1176210452007
ComponentsRed1808819820314
ComponentsBlack1734613706122
    Now let’s see how we can improve this query, by adding a WITH ROLLUP operator and GROUPING columns. By adding the WITH ROLLUP operator to the GROUP BY clause, we have added totals to the two columns we are grouping by, pc.Name and p.Color. The additional GROUPING columns help us identify the rows that represent a total. Rows where the ColorGroup is 1, and the NameGroup is 0, identify subtotals of the ProductName group. The last row where ColorGroup and NameGroup are 1 represents the query grand total.

SELECT pc.Name                      AS ProductName,
  GROUPING(pc.Name)                 AS NameGroup,
  p.Color                           AS ProductColor,
  GROUPING(p.Color)                 AS ColorGroup,
  SUM(sod.OrderQty)                 AS OrderQty,
  SUM(sod.orderqty * sod.UnitPrice) AS Sales
FROM Sales.SalesOrderDetail sod,
  Production.Product p,
  Production.ProductCategory pc
WHERE sod.ProductID          = p.ProductID
  AND p.ProductSubcategoryID = pc.ProductCategoryID
GROUP BY pc.name, p.Color WITH ROLLUP
Output:
ProductNameNameGroupProductColorColorGroupOrderQtySales
Bikes0Black01505019529109
Bikes0Silver01327117093187
Bikes0NULL12832136622296
Clothing0Blue084568425868
Clothing0Yellow062956119206
Clothing0NULL11475114545074
Components0Black01734613706122
Components0Red01808819820314
Components0Yellow01176210452007
Components0NULL14719643978443
NULL1NULL19026895145813
    Now let’s take it a step further. Using the grouping columns above, we can now replace the original ProductName and ProductColor columns with CASE statements, replacing the NULL values with the word “Total” to make it more efficient. As you can see we also incorporated the GROUPING function to the ORDER BY clause in order to get our results to sort properly and have the Total row appear on the bottom of each group as it should be.

SELECT
  CASE GROUPING(pc.Name)
    WHEN 0 THEN pc.Name
    ELSE 'Total'
  END                               AS ProductColor,
  CASE GROUPING(p.Color)
    WHEN 0 THEN p.Color
    ELSE 'Total'
  END                               AS ProductColor,
  SUM(sod.OrderQty)                 AS OrderQty,
  SUM(sod.orderqty * sod.UnitPrice) AS Sales
FROM Sales.SalesOrderDetail sod,
  Production.Product p,
  Production.ProductCategory pc
WHERE sod.ProductID          = p.ProductID
  AND p.ProductSubcategoryID = pc.ProductCategoryID
GROUP BY pc.name,p.Color WITH ROLLUP
ORDER BY GROUPING(pc.name), pc.Name, GROUPING(p.color), p.Color                
Output:
ProductColorProductColorOrderQtySales
BikesBlack1505019529109
BikesSilver1327117093187
BikesTotal2832136622296
ClothingBlue84568425868
ClothingYellow62956119206
ClothingTotal1475114545074
ComponentsBlack1734613706122
ComponentsRed1808819820314
ComponentsYellow1176210452007
ComponentsTotal4719643978443
TotalTotal9026895145813

0 comments:

Post a Comment

Twitter Delicious Facebook Digg Stumbleupon Favorites More

 
Design by Deep's | Bloggerized by Deep - Deep's Templates | ElearSQL-Server