SQL Server supports grouping of data with GROUP BY since older versions, and also offers WITH ROLLUP and WITH CUBE operators for grand-total and sub-totals. SQL Server 2008 provides a new operator named GROUPING SETS. With SQL Server 2008, it is recommended to use GROUPING SETS instead of WITH ROLLUP or WITH CUBE operators.
You can find many detailed examples about GROUPING SETS, ROLLUP and CUBE operators in this article.
And alson you can find the details of GROUP BY, WITH ROLLUP and WITH CUBE in the below articles.
“Group By Clause, SUM, MAX, MIN, AVG, COUNT and COUNT_BIG Functions in SQL Server“,
“WITH ROLLUP and WITH CUBE Operators in SQL Server(TSQL)”
Also you should read the below article too.
“GROUPING and GROUPING_ID Functions in SQL Server(TSQL)”
Let’s make examples for a better understanding of GROUPING SETS Operator.
Example:
First, we create a table with the help of the following script and add a few records into this table.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
CREATE TABLE [dbo].[Sales]( [ID] [int] NULL, [Location] [varchar](50) NULL, [Month] [varchar](50) NULL, [Category] [varchar](50) NULL, [Price] [int] NULL ) ON [PRIMARY] GO INSERT INTO [dbo].[Sales] VALUES (1,'L1','A2','K1',100), (2,'L2','A2','K1',85), (3,'L1','A2','K1',150), (4,'L1','A1','K1',90), (5,'L1','A1','K2',80), (6,'L2','A1','K2',90), (7,'L2','A1','K1',80) GO Select * FROM [dbo].[Sales] |
This table has 3 fields that we can use as a dimension. (Location, Month and Category).
We will also use the Price column as KPI / Numeric Indicator. Our goal is to see the sum of each dimension at the same time as below.
As can be seen from the result of below query, the sum of the Month and Location data appears in the same list. To do this in SQL, it is necessary to group each field and merge it with UNION.
1 2 3 4 5 6 7 |
SELECT '' AS [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Month] UNION ALL SELECT [Location], '' [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location] |
In this way, when we want to include more than one dimension, we must create a UNION series for each. The GROUPING SETS clause that comes with SQL Server 2008 offers both flexibility and performance. This sentence, which is compatible with ANSI SQL 2006, can be considered as a function used with GROUP BY. As a parameter, it is enough to write the columns to be aggregated.
1 2 3 4 5 6 7 8 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( [Location], [Month] ) |
Or let’s replace NULL values to get exactly the same image in our example.
1 2 3 4 5 6 7 8 |
SELECT ISNULL([Location],'') AS Location, ISNULL([Month],'') AS Month, SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( [Location], [Month] ) |
Using the three dimensions in our example, let’s calculate all possibilities separately without GROUPING SETS and using GROUPING SETS.
1 2 3 4 5 6 7 8 9 10 11 12 |
SELECT NULL AS [Location], [Month], [Category], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Month],[Category] UNION ALL SELECT [Location], NULL [Month], [Category], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location],[Category] UNION ALL SELECT [Location], [Month], NULL [Category], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location],[Month] Order By [Location] |
1 2 3 4 5 6 7 8 9 10 |
SELECT [Location], [Month], [Category], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( ([Month], [Category]), ([Location], [Category]), ([Location], [Month]) ) Order By [Location] |
When you run the above two queries, a result returns as follows.
Let’s calculate the sub-total and grand-total by using the Location and Month dimensions.
1 2 3 4 5 6 7 8 9 10 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location], [Month] UNION SELECT [Location], NULL, SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location] UNION SELECT NULL, NULL, SUM(Price) Endorsement FROM [dbo].[Sales] |
To make it clearer, let’s sort:
1 2 3 4 5 6 7 8 9 10 11 12 |
SELECT * FROM ( SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location], [Month] UNION SELECT [Location], NULL, SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location] UNION SELECT NULL, NULL, SUM(Price) Endorsement FROM [dbo].[Sales] ) as T ORDER BY ISNULL([Location],'ZZZZ'), ISNULL([Month],'ZZZZ') |
Instead of combining this type of process with UNION for each dimension, we do this with WITH ROLLUP or WITH CUBE. So we’ll get the same result with an easier typing.
1 2 3 4 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location], [Month] WITH ROLLUP |
To get the same result as GROUPING SETS, we need to write the fields to be aggregated.
1 2 3 4 5 6 7 8 9 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( ([Location], [Month]), [Location], () ) |
As you can see, there is flexibility in the GROUPING SETS method. WITH ROLLUP automatically creates a grand total for all fields grouped, while GROUPING SETS creates only for what we do. For example, if you do not want to calculate the grand total, simply remove the line “()” in GROUPING SETS.
GROUPING SETS without Grand Total:
1 2 3 4 5 6 7 8 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( ([Location], [Month]), [Location] ) |
GROUPING SETS without Sub Total and Grand Total:
1 2 3 4 5 6 7 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( ([Location], [Month]) ) |
GROUPING SETS with only Grand Total:
1 2 3 4 5 6 7 8 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( ([Location], [Month]), () ) |
Let’s add the “Month” field to GROUPING SETS. Thus, all possible aggregated rows will be created for Location and Month fields. We were doing this with WITH CUBE.
WITH CUBE Method:
1 2 3 4 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY [Location], [Month] WITH CUBE |
WITH GROUPING SETS Method:
The order of use of the dimensions in GROUPING SETS is not important. It always returns the same result.
1 2 3 4 5 6 7 8 9 10 |
SELECT [Location], [Month], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( ([Location], [Month]), [Location], [Month], () ) |
Let’s add 3 fields in our example without grand-total.
1 2 3 4 5 6 7 8 9 10 |
SELECT [Location], [Month], [Category], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( ([Location], [Month], [Category]), ([Location], [Month]), [Location], [Month] ) |
One of the advantages offered by GROUPING SETS is that sub-totals can only be created for certain columns. In our previous example, a sub-total row was created for all groups. However, we can create a sub-total for the Month and Category by fixing the location.
1 2 3 4 5 6 7 |
SELECT [Location], [Month], [Category], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( [Location], ROLLUP([Month], [Category]) ) |
Another Example:
1 2 3 4 5 6 7 |
SELECT [Location], [Month], [Category], SUM(Price) Endorsement FROM [dbo].[Sales] GROUP BY GROUPING SETS ( [Location], [Category], ROLLUP([Month]) ) |
CONCLUSION:
With SQL Server 2008, it is recommended to use GROUPING SETS instead of WITH ROLLUP or WITH CUBE operators.