Adding Grand Totals in Pivot Table - sql-server

I have created a pivot table with the following code:
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #Columns AS VARCHAR (MAX)
SELECT #Columns =
COALESCE(#Columns + ', ','')+ QUOTENAME(PortfolioID)
FROM
(
SELECT PortfolioID FROM InfoPortal.DBO.fn_Generic_PortfolioGroupMembers (#PortfolioGroup)
) AS B
ORDER BY B.PortfolioID
SET #SQL = '
WITH PivotData AS
(
SELECT
PortfolioID, Percentage, DurationBand, DurationSort
FROM #Worktable
)
SELECT
DurationBand,
' + #Columns + '
FROM PivotData
PIVOT
(
SUM(Percentage)
FOR PortfolioID
IN (' + #Columns + ')
) AS PivotResult
ORDER BY DurationSort'
EXEC (#SQL)
However what i would like to do is add grand totals for each portfolioID, and i'm unsure of how to achieve this. Any help?

You should be able to add a GROUP BY with ROLLUP to produce the totals row, similar to this:
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #Columns AS VARCHAR (MAX)
DECLARE #ColumnsRollup AS VARCHAR (MAX)
SELECT #Columns =
COALESCE(#Columns + ', ','')+ QUOTENAME(PortfolioID)
FROM
(
SELECT distinct PortfolioID
FROM worktable
) AS B
ORDER BY B.PortfolioID
SELECT #ColumnsRollup =
COALESCE(#ColumnsRollup + ', Sum(','Sum(')+ QUOTENAME(cast(PortfolioID as varchar(10)))+') as Portfolio'+cast(PortfolioID as varchar(10))
FROM
(
SELECT distinct PortfolioID
FROM worktable
) AS B
ORDER BY B.PortfolioID
SET #SQL = '
WITH PivotData AS
(
SELECT PortfolioID, Percentage, DurationBand, DurationSort
FROM Worktable
)
SELECT case when DurationBand is not null then cast(durationband as varchar(10))
else ''Total'' end Durationband, ' + #ColumnsRollup+ '
FROM
(
SELECT DurationBand, ' + #Columns + '
FROM PivotData
PIVOT
(
SUM(Percentage)
FOR PortfolioID IN (' + #Columns + ')
) AS PivotResult
) src
GROUP BY DurationBand with ROLLUP'
EXEC (#SQL)
See SQL Fiddle with Demo. Note: sample data is just mocked based on your table structure.
Result:
| DURATIONBAND | PORTFOLIO1 | PORTFOLIO2 | PORTFOLIO3 |
-------------------------------------------------------
| 2 | 78 | (null) | (null) |
| 5 | (null) | (null) | 4 |
| 12 | 10 | 45 | (null) |
| Total | 88 | 45 | 4 |
Based in the need to keep things sorted, you can use:
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #Columns AS VARCHAR (MAX)
DECLARE #ColumnsRollup AS VARCHAR (MAX)
SELECT #Columns =
COALESCE(#Columns + ', ','')+ QUOTENAME(PortfolioID)
FROM
(
SELECT distinct PortfolioID
FROM worktable
) AS B
ORDER BY B.PortfolioID
SELECT #ColumnsRollup =
COALESCE(#ColumnsRollup + ', Sum(','Sum(')+ QUOTENAME(cast(PortfolioID as varchar(10)))+') as '+QUOTENAME(cast(PortfolioID as varchar(10)))
FROM
(
SELECT distinct PortfolioID
FROM worktable
) AS B
ORDER BY B.PortfolioID
SET #SQL = '
WITH PivotData AS
(
SELECT PortfolioID, Percentage, DurationBand, DurationSort
FROM Worktable
)
SELECT *
FROM
(
SELECT DurationBand, ' + #Columns + '
FROM PivotData
PIVOT
(
SUM(Percentage)
FOR PortfolioID IN (' + #Columns + ')
) AS PivotResult
UNION ALL
select ''Grand Total'', '+#ColumnsRollup+'
from
(
SELECT DurationBand, ' + #Columns + '
FROM PivotData
PIVOT
(
SUM(Percentage)
FOR PortfolioID IN (' + #Columns + ')
) AS PivotResult
)tot
) src
'
EXEC (#SQL)
See SQL Fiddle with Demo

Related

Column pivot problem getting repeated Id with pivot columns having null values

At the top the result of my pivot and below is the original table
I want a result like this
AssetId | 77 | 78 | 79 | 80 | 81 | 82
1571539 | 99 |01/01/2020 | L460 | Avast Pro| 01/30/2020| NULL
8323444 | 103|01/28/2020 |PhoneI| Avast Pro| Null | NULL
#pAssetTypeId int
as
IF OBJECT_ID('tempdb..##TBL_TEMP') IS NOT NULL
DROP TABLE #TBL_TEMP
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
DECLARE #AssetId AS Varchar(MAX)
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') + QUOTENAME(fm.FieldMaintenanceId)
FROM dbo.FieldData f
LEFT JOIN dbo.AssetType a
ON f.AssetTypeId = a.AssetTypeId
LEFT JOIN dbo.FieldMaintenance fm
ON f.FieldMaintenanceId = fm.FieldMaintenanceId
where a.AssetTypeId = #pAssetTypeId
SET #SQLQuery =
N'SELECT AssetId,' + #PivotColumns + '
INTO #TBL_TEMP
FROM [dbo].[AssetDetails] a
PIVOT( MAX([Data])
FOR [FieldMaintenanceId] IN (' + #PivotColumns + ')) as Q'
EXEC sp_executesql #SQLQuery
Select * from #TBL_TEMP
Click to see desired pivot result
IF OBJECT_ID('tempdb..##TBL_TEMP') IS NOT NULL
DROP TABLE ##TBL_TEMP
DECLARE #SQLQuery AS NVARCHAR(MAX)
DECLARE #PivotColumns AS NVARCHAR(MAX)
DECLARE #AssetId AS Varchar(MAX)
SELECT #PivotColumns= COALESCE(#PivotColumns + ',','') +
QUOTENAME(fm.FieldMaintenanceId)
FROM CONCEPASSET.dbo.FieldData f
LEFT JOIN CONCEPASSET.dbo.AssetType a
ON f.AssetTypeId = a.AssetTypeId
LEFT JOIN CONCEPASSET.dbo.FieldMaintenance fm
ON f.FieldMaintenanceId = fm.FieldMaintenanceId
where a.AssetTypeId = 3
SET #SQLQuery =
N'Select *
from
(
Select
AssetId,
AssetTypeId,
FieldMaintenanceId,
[Data]
from AssetDetails ) AS SourceTable PIVOT(MAX([Data]) FOR [FieldMaintenanceId]
IN('+#PivotColumns+')) AS TableTest '
EXEC sp_executesql #SQLQuery
Reworked the code and it worked thank you all!!

Replacing null values in dynamic pivot sql query

Image transcription:
FTE/RATE CARD | 2018-01-01 | 2018-02-01 | 2018-03-01 | 2018-04-01 | 2018-05-01 | 2018-06-01 | ...
-------------------------------------------------------------------------------------------------
FTE 3 | NULL | NULL | NULL | 33 | 38 | 40.5 | ...
I have a pivot sql query as below.
I need to replace NULL values with Zeros in the result.
I don't know where do I exactly use the IsNull or Coalesce function in the query.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF
(
(
SELECT distinct ',' + QUOTENAME([MONTH])
FROM [HEADCOUNT]
WHERE [MONTH] BETWEEN '01-012018' AND '12-01-2018'
ORDER BY ',' + QUOTENAME([MONTH])
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,''
)
SET #query = 'SELECT [FTE/RATE CARD],' + #cols + ' FROM
(
SELECT [MONTH],[FTE/RATE CARD],[HC]
FROM [HEADCOUNT]
WHERE [CC-LOC] IN ([CC-LOC])
) x pivot (Sum ([HC]) for [MONTH] in (' + #cols + '))p' execute(#query)
You'll need to generate another column list for the select statement, and wrap individual months with ISNULL, like so:
DECLARE #cols AS NVARCHAR(MAX),
#selectCols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #selectCols = STUFF
(
(
SELECT distinct ', ISNULL(' + QUOTENAME([MONTH]) + ', 0) AS ' + QUOTENAME([MONTH])
FROM [HEADCOUNT]
WHERE [MONTH] BETWEEN '01-012018' AND '12-01-2018'
ORDER BY ',' + QUOTENAME([MONTH])
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,''
)
SELECT #cols = STUFF
(
(
SELECT distinct ',' + QUOTENAME([MONTH])
FROM [HEADCOUNT]
WHERE [MONTH] BETWEEN '01-012018' AND '12-01-2018'
ORDER BY ',' + QUOTENAME([MONTH])
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'),1,1,''
)
SET #query = 'SELECT [FTE/RATE CARD],' + #selectCols + ' FROM
(
SELECT [MONTH],[FTE/RATE CARD],[HC]
FROM [HEADCOUNT]
WHERE [CC-LOC] IN ([CC-LOC])
) x pivot (Sum ([HC]) for [MONTH] in (' + #cols + '))p' execute(#query)

SQL Dynamic Pivot Table [duplicate]

This question already has answers here:
Efficiently convert rows to columns in sql server
(5 answers)
Closed 6 years ago.
I'm struggling with an error while making a dynamic pivot table
The source data is
JobID | SalesForMonth | YearMonth
7734 | 400 | 2016-12
7734 | 350 | 2017-01
8540 | 444 | 2016-12
8540 | 300 | 2017-01
and aiming for
JobID | 2016-12 | 2017-01
7734 | 400 | 350
8540 | 444 | 300
and I've tried to use a query I found on here to create the column headers. But must admit I don't really understand the 'For XML' line and getting a syntax error there on line 6
DECLARE
#cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(YearMonth)
FROM v_JobSalesByMonth
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'')
SELECT #query =
'SELECT * FROM
(SELECT JobID, YearMonth, SalesForMonth
FROM v_JobSalesByMonth) X
PIVOT
(
(JobID, SalesForMonth)
for [YearMonth] in (' + #cols + ')
) P'
I'd also like to stick in a 'total sales' for the jobID column
Any help would be much appreciated
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From v_JobSalesByMonth Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Select [JobID],[TotalSales],' + #SQL + '
From (
Select JobID
,TotalSales = sum(SalesForMonth) over (Partition By JobID)
,YearMonth
,SalesForMonth
From v_JobSalesByMonth A
) A
Pivot (sum(SalesForMonth) For [YearMonth] in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
EDIT - Dynamically Create View
Since you can't have dynamic SQL in a view, you could have job scheduled (daily or monthly) to drop and re-create the view.
if object_id('vw_SalesByMonth','v') is not null
drop view vw_SalesByMonth;
Declare #SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(YearMonth) From Yourtable Order by 1 For XML Path('')),1,1,'')
Select #SQL = '
Create View vw_SalesByMonth
AS
Select [JobID],[TotalSales],' + #SQL + '
From (
Select JobID
,TotalSales = sum(SalesForMonth) over (Partition By JobID)
,YearMonth
,SalesForMonth
From YourTable A
) A
Pivot (sum(SalesForMonth) For [YearMonth] in (' + #SQL + ') ) p'
Exec(#SQL);
Select * from vw_SalesByMonth

Count non-empty rows with unknown column names

Given a table that has unknown column names, how can I list all column names and the amount of rows that have a non-empty (NULL or empty string) value in that column?
Small example:
Col1 | Col2 | Col3 | dkasldk | dD? d3# !(
1 | | 2 | |
| 2 | d | ddd939 |
f | f | 84 | |
Should yield:
Column Name | Values
Col1 | 2
Col2 | 2
Col3 | 3
dkasldk | 1
dD? d3# !( | 0
I already tried around with using INFORMATION_SCHEMA.COLUMNS and creating dynamic SQL queries, but to no avail:
select N'select c.COLUMN_NAME,
(select sum(case when p.' + QUOTENAME(c.COLUMN_NAME) + ' != '''' then 1 else 0 end) from [Produkte] p) [Produkte]
from INFORMATION_SCHEMA.COLUMNS c
where c.TABLE_NAME = ''Produkte'' and c.COLUMN_NAME = ''' + c.COLUMN_NAME + '''' select_statement
from INFORMATION_SCHEMA.COLUMNS c
where c.TABLE_NAME = 'Produkte'
I cannot quite wrap my head around how to combine the two problems (for which I did find solution in their own, but not the combination) of Dynamic Column Names and Count empty values...
You can do something like this using UNPIVOT..
DECLARE #TableName NVARCHAR(MAX) = N'Produkte',
#CountColumns NVARCHAR(MAX),
#Columns NVARCHAR(MAX),
#Sql NVARCHAR(MAX)
SELECT #CountColumns = COALESCE(#CountColumns + ',', '') + 'COUNT(NULLIF(' + QUOTENAME(c.COLUMN_NAME) + ','''')) AS ' + QUOTENAME(c.COLUMN_NAME),
#Columns = COALESCE(#Columns + ',', '') + QUOTENAME(c.COLUMN_NAME)
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME = #TableName
SET #SQL = 'SELECT [Column Name], [Values]
FROM (
SELECT '
+ #CountColumns + '
FROM ' + #TableName + '
) t
UNPIVOT (
[Values]
FOR [Column Name] IN (' + #Columns + ')
) up
'
EXEC(#SQL)
SQL Fiddle Demo
You can use a dynamic UNPIVOT.
Using these variables:
DECLARE #qry NVARCHAR(MAX)
DECLARE #cols NVARCHAR(MAX) = ''
you can select columns names in a format suitable for the UNPIVOT operation with the following dynamic sql:
SELECT #cols = STUFF((SELECT ',[' + c.COLUMN_NAME + ']'
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME = 'Produkte'
FOR XML PATH('')), 1, 1, '')
Finally use #cols to build the query:
SET #qry = 'SELECT t.Col, COUNT(*)
FROM (SELECT Val, Col
FROM Produkte
UNPIVOT (
Val FOR Col IN (' + #cols + ')) unpvt
) AS t
WHERE t.Val <> '''' OR t.Val IS NOT NULL
GROUP BY t.Col'
... and execute it to get desired result:
EXEC(#qry)
Ultimately the SQL you are after is something like this:
SELECT ColumnName, NonEmpty
FROM ( SELECT A = 1,
[Col1] = COUNT(CASE WHEN [Col1] <> '' THEN 1 END),
[Col2] = COUNT(CASE WHEN [Col2] <> '' THEN 1 END),
[Col3] = COUNT(CASE WHEN [Col3] <> '' THEN 1 END),
[dkasldk] = COUNT(CASE WHEN [dkasldk] <> '' THEN 1 END),
[dD? d3# !(] = COUNT(CASE WHEN [dD? d3# !(] <> '' THEN 1 END)
FROM #T
) AS t
UNPIVOT
( NonEmpty
FOR ColumnName IN ([Col1],[Col2],[Col3],[dkasldk],[dD? d3# !(])
) AS upvt;
UNPIVOT Will convert your data from
Col1 Col2 Col3
-------------------------
1 3 2
To the format you require:
ColumnName NonEmpty
-------------------------
Col1 1
Col2 3
Col3 2
You can build up dynamically using something like this:
-- SAMPLE DATA
USE TempDB;
CREATE TABLE #T
(
[Col1] VARCHAR(1),
[Col2] VARCHAR(1),
[Col3] VARCHAR(2),
[dkasldk] VARCHAR(6),
[dD? d3# !(] VARCHAR(1)
);
INSERT #T ([Col1], [Col2], [Col3], [dkasldk], [dD? d3# !(])
VALUES
('1', NULL, '2', NULL, ''),
('', '2', 'd', 'ddd939', NULL),
('f', 'f', '84', NULL, '');
DECLARE #TableName SYSNAME = '#T';
-- VALID INPUT TABLE
IF OBJECT_ID(#TableName, 'U') IS NULL
AND OBJECT_ID(#TableName, 'V') IS NULL
BEGIN
PRINT 'Invalid table or View';
RETURN
END
-- BUILD DYNAMIC SQL
DECLARE #SQL NVARCHAR(MAX) =
CONCAT('SELECT ColumnName, NonEmpty FROM (SELECT A = 1, ' ,
STUFF(( SELECT CONCAT(',',
QUOTENAME(name),
' = COUNT(CASE WHEN ',
QUOTENAME(Name),
' <> '''' THEN 1 END)')
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#TableName)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
' FROM ',
#TableName,
') AS t UNPIVOT (NonEmpty FOR ColumnName IN (',
STUFF(( SELECT CONCAT(',', QUOTENAME(name))
FROM sys.columns
WHERE [object_id] = OBJECT_ID(#TableName)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)'), 1, 1, ''),
')) AS upvt');
-- EXECUTE DYNAMIC SQL
EXECUTE sp_executesql #SQL;

How to get this output using sql query,I have two tables ServayQues1 and ServayQuesAns1

select A.QueId,Question,Answer from
ServayQues1 as S inner join ServayQuesAns1 as A
on S.QueId=A.QueId
QueId | Question | Answer
----------------------------
1 test Ok
1 test not bad
1 test need to be improve
----------------------------
My expected output is below
QueId | Question | answer1 | answer2 | answer3
--------------------------------------------------------------------------
1 test Ok not bad need to be improve
---------------------------------------------------------------------------
How do I get this output?
Hope this is what you need.
DECLARE #PivotColumnHeaders VARCHAR(MAX)
SELECT #PivotColumnHeaders = COALESCE(
#PivotColumnHeaders + ',[' + cast([answer] as varchar) + ']',
'[' + cast([answer] as varchar)+ ']')
FROM (SELECT DISTINCT Answer from
ServayQues1 as S inner join ServayQuesAns1 as A
on S.QueId=A.QueId) s
DECLARE #PivotTableSQL NVARCHAR(MAX)
SET #PivotTableSQL = N'
SELECT *
FROM
(
SELECT A.QueId,Question,Answer
FROM ServayQuesAns1 A inner join
ServayQues1 q on q.QueId= a.QueId
) AS source
PIVOT
(
MAX([Answer])
FOR [Answer] IN (
' + #PivotColumnHeaders + '
)
) AS PivotTable
'
print #PivotTableSQL
EXECUTE(#PivotTableSQL)

Resources