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)
Related
Morning all, Longtime lurker, first time poster.
I'm writing a stored procedure to take the results from one SELECT statement and use that output to build another SELECT statement. Trouble is I can not find a mechanism or code to accomplish this. Assigning the results to a variable doesn't seem to be an option because SQL doesn't support Arrays (that I know of).
+----+-------------+-------------+
| ID | ___$seqval | Column_Name |
+----+-------------+-------------+
| 1 | 0x000000E10 | EnvType |
| 2 | 0x000000E10 | DataType |
| 3 | 0x000000E10 | DateMod |
+----+-------------+-------------+
Trying to get to;
SELECT Column_name(1), Column_name(2)..
From tblServer_Data
There could be up to a total of 20 columns returned.
SQL DEMO
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME([Column_Name])
FROM Table1 c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
SELECT #cols as Columns; -- just for debug
set #query = 'SELECT [ID], ' + #cols + ' from
(
select 1 as ID
, [seqval]
, [Column_Name]
from Table1
) x
pivot
(
max([seqval])
for [Column_Name] in (' + #cols + ')
) p '
SELECT #query as Query; -- just for debug
execute(#query);
OUTPUT
Then you can do SELECT over that output
This will give a SELECT statement of the columns in a selected table.
SELECT 'SELECT ' + STUFF(
(SELECT ',' + c.column_name from
(SELECT TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS c
where c.TABLE_NAME = your_table) c
for xml path ('')),1,1,'') + ' FROM ' + your_table
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
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME(Symbol)
from Opt
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Date,' + #cols + ' from
(
select Date, Symbol, Price
from Opt
)x
pivot
(
max(Price)
for Symbol in (' + #cols + ')
) p'
execute(#query);
I get this from the above code:
Symbols(varchar50) Date price quantity
apple 14/11/2016 30 15
banana 14/11/2016 22 20
i need like this
Date apple_price apple_quantity banana_price banana_quantity
14/11/2016 30 15 22 10
from above code i get only price
Just a minor twist to your original. Notice the sub-query/Union All.
Declare #SQL varchar(max)
Select #SQL = Stuff((Select Distinct
',' + QuoteName(Symbol+'_Price')
+ ',' + QuoteName(Symbol+'_Quantity')
From Opt For XML Path('')),1,1,'')
Select #SQL = 'Select Date,' + #SQL + '
From (
Select Date,Item=Symbol+''_Price'',Val=Price From Opt
Union All
Select Date,Item=Symbol+''_Quantity'',Val=Quantity From Opt
) A
Pivot (max(Val) For Item in (' + #SQL + ') ) p'
Exec(#SQL);
Returns
Date apple_Price apple_Quantity banana_Price banana_Quantity
2016-11-14 30 15 22 20
I have a Problem converting rows in columns of a SQL Result.
My structure is like this:
GUID | PropertyName | PropertyValue
abcd | DistinguishedName | cn=abcd...
abcd| CN | cn= GROUP_
abcd| Operation | ADD
1231 | DistinguishedName| cn=123dd
1231 | Cn | cn=ASDGRUOP
1231 | Operation | DEL
There can be n PropertyNames that I dont know before, they are dynamically - i can get them through an SQL, that is not the Problem.
I want to have a structure like this:
GUID | DistinguishedName | CN | Operation
abcd| cn=abcd...| cn= GROUP_ | ADD
1231 | cn=123dd | cn=ADSGROUP | DEL
and so on.
The Column-Headers i get by this SQL:
select #cols = STUFF (( SELECT DISTINCT '],[' + x.ParameterName from ... and parametername in ('PropertyValue','DistinguishedName', 'Operation')
FOR XML PATH ('')),1,2,'') + ']'
I can do this with PIVOT-Function but because i dont have Aggregation, I cant get the right result:
set #query = N'SELECT '+ #cols + ' FROM (
SELECT x.parametervalue, x.parametername
from ... and parametername in (''PropertyValue'',''DistinguishedName'', ''Operation'')
) a
PIVOT (max(a.parametervalue) FOR ParameterName in ( ' + #cols + ')) as pv;'
exec sp_executesql #query;
I get the following result:
GUID | DistinguishedName | CN | Operation | ... other Propertys
abcd | cn=abcd... | cn = GROUP_ |ADD |...
Only 1 Result - not more. But there are like 700 Results from this query, because of the MAX() function i get only one. How can I get a Pivot without Aggregation to get all of the results?
Thank you in Advance!
Here is the dynamic PIVOT query:
DECLARE #sql NVARCHAR(MAX),
#cols NVARCHAR(MAX);
SELECT #cols =
STUFF((
SELECT DISTINCT ',' + QUOTENAME(PropertyName)
FROM #tbl
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
, 1, 1, '')
SELECT #sql =
'SELECT GUID, ' + #cols + '
FROM (
SELECT
GUID, PropertyName, PropertyValue
FROM #tbl
) t
PIVOT
(
MAX(PropertyValue)
FOR PropertyName IN(' + #cols + ')
) p ';
PRINT (#sql);
EXEC (#sql);
ONLINE DEMO
Another way to achieve the desired result is to use a dynamic crosstab:
DECLARE #sql NVARCHAR(MAX);
SELECT #sql =
'SELECT
GUID' + CHAR(10) +
(SELECT DISTINCT
' , MAX(CASE WHEN PropertyName = ''' + PropertyName + ''' THEN PropertyValue END) AS ' + QUOTENAME(PropertyName) + CHAR(10)
FROM #tbl
FOR XML PATH('')
) +
'FROM #tbl
GROUP BY GUID;';
PRINT (#sql);
EXEC (#sql);
ONLINE DEMO
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