Introduction
Microsoft SQL Server has introduced the PIVOT
and UNPIVOT
commands as enhancements to T-SQL with the release of Microsoft SQL Server 2005. Pivot Table in SQL has the ability to display data in custom aggregation. PIVOT
rotates a table-valued expression by turning the unique values from one column in the expression into multiple columns in the output, and performs aggregations where they are required on any remaining column values that are wanted in the final output. UNPIVOT
performs the opposite operation to PIVOT
by rotating columns of a table-valued expression into column values.
More information on Pivot.
In this article, I’m concentrating on how to display Grand Total row and column for the pivot table as shown in the below grid view:
Here in the grid, I’m showing the number of matches played by a team in each month. At last, I need to show the grand total for each team (Last column) - this total gives the year count for the teams. In the same way, I need a grand total row as last row in grid, which will give the number of matches played by all the teams for that particular month.
Background
Usually as a .NET developer, first I will get the pivot table from the stored procedure to dataset and grand total row and column. I will manipulate in the C#/ VB code using Datatable
(Datatable compute method for better performance). But in this article, I want to show how to get the grand total row and column from the stored procedure, so that we can directly display data in the grid without any manipulation in the C#/VB.
How It Works
Here I’m using pivot with dynamic columns, most questions were about the column list in the PIVOT
statement. This list is fixed, but many times the new columns are determined by the report at a later stage. This problem is easily solved when we mix pivots with dynamic SQL, so here is a very simple script about how to dynamically generate the pivot
statement:
DECLARE @cols NVARCHAR (MAX)
SELECT @cols = COALESCE (@cols + ',[' + colName + ']', '[' + colName + ']')
FROM Table1
WHERE Conditions
ORDER BY colName
PRINT @cols
The above script gives you the list of columns in string
format with commas. Example: [Jan], [Feb], [Mar], [Apr], [May], [Jun], [Jul], [Aug], [Sept], [Oct], [Nov], [Dec]
. If you pass this dynamic query to your pivot, then your pivot columns will display dynamically.
The below SQL script creates the stored procedure which returns pivot table as output.
CREATE PROCEDURE pivot_TeamVsMatches
AS
DECLARE @columnHeaders NVARCHAR (MAX)
SELECT @columnHeaders = _
COALESCE (@columnHeaders + ',[' + month + ']', '[' + month + ']')
FROM tbl_Matches
ORDER BY month
DECLARE @FinalQuery NVARCHAR(MAX)
SET @FinalQuery = ‘SELECT *
FROM
(SELECT Team,
Month
FROM tbl_Matches
) A
PIVOT
(
COUNT(*)
FOR ColName
IN (‘+@columnHeaders +’)
) B
ORDER BY Team’
PRINT ‘Pivot Queuery :’+ @FinalQuery
EXECUTE (@FinalQuery)
GO
This stored procedure returns pivot table as below:
Now to get the grand total and row, we need to form the COALESCE
query. As shown below…
DECLARE @GrandTotalCol NVARCHAR (MAX)
SELECT @GrandTotalCol = COALESCE (@GrandTotalCol + ‘ISNULL _
([' + CAST (Month AS VARCHAR) +'],0) + ', 'ISNULL([' + CAST(Month AS VARCHAR)+ '],0) + ')
FROM tbl_Matches
GROUP BY Month
ORDER BY Month
SET @GrandTotalCol = LEFT (@GrandTotalCol, LEN (@GrandTotalCol)-1)
The above query returns as below…
@GrandTotalCol = ISNULL ([' + CAST (Jan AS VARCHAR) +'],0) + ISNULL _
([' + CAST (Feb AS VARCHAR) +'],0) + ISNULL ([' + CAST (March AS VARCHAR) +'],0) + _
…………. + ISNULL ([' + CAST (Dec AS VARCHAR) +'],0).
DECLARE @GrandTotalRow NVARCHAR(MAX)
SELECT @GrandTotalRow = COALESCE(@GrandTotalRow + ',ISNULL(SUM([' + _
CAST(Month AS VARCHAR)+']),0)', 'ISNULL(SUM([' + CAST(Month AS VARCHAR)+']),0)')
FROM tbl_Matches
GROUP BY Month
ORDER BY Month
The above query returns as below…
@GrandTotalRow = ISNULL(SUM([' + CAST(Jan AS VARCHAR)+']),0) + _
ISNULL(SUM([' + CAST(Feb AS VARCHAR)+']),0) + ……… + _
ISNULL(SUM([' + CAST(Dec AS VARCHAR)+']),0).
The above COALESCE string
s need to be used in dynamic pivot query…
Below is the stored procedure which will give the total output of our requirement.
CREATE PROCEDURE pivot_TeamVsMatches
AS
DECLARE @columnHeaders NVARCHAR (MAX)
SELECT @columnHeaders = COALESCE (@columnHeaders _
+ ',[' + month + ']', '[' + month + ']')
FROM tbl_Matches
GROUP BY month
ORDER BY month
DECLARE @GrandTotalCol NVARCHAR (MAX)
SELECT @GrandTotalCol = COALESCE (@GrandTotalCol + ‘ISNULL ([' + _
CAST (Month AS VARCHAR) +'],0) + ', 'ISNULL([' + CAST(Month AS VARCHAR)+ '],0) + ')
FROM tbl_Matches
GROUP BY Month
ORDER BY Month
SET @GrandTotalCol = LEFT (@GrandTotalCol, LEN (@GrandTotalCol)-1)
/* GRAND TOTAL ROW */
DECLARE @GrandTotalRow NVARCHAR(MAX)
SELECT @GrandTotalRow = COALESCE(@GrandTotalRow + ',ISNULL(SUM([' + _
CAST(Month AS VARCHAR)+']),0)', 'ISNULL(SUM([' + CAST(Month AS VARCHAR)+']),0)')
FROM tbl_Matches
GROUP BY Month
ORDER BY Month
/* MAIN QUERY */
DECLARE @FinalQuery NVARCHAR (MAX)
SET @FinalQuery = ‘SELECT *, ('+ @GrandTotalCol + ') _
AS [Grand Total] INTO #temp_MatchesTotal
FROM
(SELECT Team,
Month
FROM tbl_Matches
) A
PIVOT
(
COUNT (*)
FOR ColName
IN (‘+@columnHeaders +’)
) B
ORDER BY Team
SELECT * FROM #temp_MatchesTotal UNION ALL
SELECT ''Grand Total'','''','+@GrandTotalRow +', _
ISNULL (SUM([Grand Total]),0) FROM #temp_MatchesTotal
DROP TABLE #temp_MatchesTotal'
EXECUTE(@PivotQuery)
GO
Result as below…
Here in this stored procedure, I have used a temporary table to get the grand total row. I did the UNION ALL
with temporary table; don’t forget to drop the temporary table.
For any queries & suggestions, mail me @ narapareddy.shyam@gmail.com. By using some third party controls also we can achieve this, but here I concentrated only on typical/ normal SQL query. If anybody has any efficient and different ways, kindly share with me.
Thanks again. Bye.