Sqlserver table Row to column data - pivot table - sql-server

I have an Excel-sheet as below, I already dump the data into database (as the sample data below) from this excel in normalized form.
Now I want to get the similar view of excel from database's data. I tried this, but given in wrong format. Good if somebody given the same result view as excel with column name and inner join.
I do not want to hardcore as the year expand.
declare #tblyear table(id int, year int)
insert into #tblyear values (1,2012), (2,2013),(3,2014) ,(4,2015),(5,2016)
declare #ChargeableYearDetails table ( id int, year int, CumulativeHrs numeric(18,2), CumulativeChargeableHrs numeric(18,2))
--take only 2 row year wise for the sample
insert into #ChargeableYearDetails values
(1, 1, 1657.75, 1243.50),
(2, 1, 3925.50, 3044.75),
(3, 2, 870.25, 568.25),
(4, 2, 2517.75, 1808.00),
(5, 3, 189.50, 99.00),
(6, 3, 1982.75, 1295.25),
(7, 4, 539.00, 351.00),
(8, 4, 2542.75, 1924.75),
(9, 5, 874.50, 596.50),
(9, 5, 2721.50, 2175.50)
select * from #tblyear
select * from #ChargeableYearDetails
/*I tried this , but given wrong result*/
select * from #ChargeableYearDetails
pivot
(
max(CumulativeHrs)
FOR year in ([1],[2],[3],[4],[5])
) as p

My answer is a little bit complicated, but I should post it. I use dynamic sql and pivoting.
DECLARE #columnsH nvarchar(500),
#columnsCH nvarchar(500),
#columns nvarchar(1000),
#sql nvarchar(4000)
CREATE TABLE #tblyear (id int, [year] int)
INSERT INTO #tblyear VALUES (1,2012), (2,2013),(3,2014) ,(4,2015),(5,2016)
CREATE TABLE #ChargeableYearDetails (id int, [year] int, CumulativeHrs numeric(18,2), CumulativeChargeableHrs numeric(18,2))
INSERT INTO #ChargeableYearDetails VALUES
(1, 1, 1657.75, 1243.50),(2, 1, 3925.50, 3044.75),(3, 2, 870.25, 568.25),
(4, 2, 2517.75, 1808.00),(5, 3, 189.50, 99.00),(6, 3, 1982.75, 1295.25),
(7, 4, 539.00, 351.00),(8, 4, 2542.75, 1924.75),(9, 5, 874.50, 596.50),
(9, 5, 2721.50, 2175.50)
SELECT #columnsH = STUFF((SELECT DISTINCT ',' + QUOTENAME('CumulativeHrsYY'+ CAST([Year] AS NVARCHAR(4))) FROM #tblyear FOR XML PATH('')),1,1,'')
SELECT #columnsCH = STUFF((SELECT DISTINCT ',' + QUOTENAME('CumulativeChargeableHrs'+ CAST([Year] AS NVARCHAR(4))) FROM #tblyear FOR XML PATH('')),1,1,'')
SELECT #columns = STUFF((SELECT DISTINCT ',' + QUOTENAME('CumulativeHrsYY'+ CAST([Year] AS NVARCHAR(4))) +',' + QUOTENAME('CumulativeChargeableHrs'+ CAST([Year] AS NVARCHAR(4))) FROM #tblyear FOR XML PATH('')),1,1,'')
SELECT #sql = '
SELECT '+ #columns+'
FROM (
SELECT *
FROM (
SELECT ''CumulativeHrsYY''+ CAST(t.[Year] AS NVARCHAR(4)) as [Year],
c.CumulativeHrs,
ROW_NUMBER() OVER (PARTITION BY c.[year] ORDER BY c.[year]) as rn
FROM #ChargeableYearDetails c
LEFT JOIN #tblyear t
ON t.ID = c.[year]
) as t
pivot
(
max(CumulativeHrs)
FOR [year] in ('+#columnsH+')
) as p
) as part1
LEFT JOIN (
SELECT *
FROM (
SELECT ''CumulativeChargeableHrs''+ CAST(t.[Year] AS NVARCHAR(4)) as [Year],
c.CumulativeChargeableHrs,
ROW_NUMBER() OVER (PARTITION BY c.[year] ORDER BY c.[year]) as rn
FROM #ChargeableYearDetails c
LEFT JOIN #tblyear t
ON t.ID = c.[year]
) as t
pivot
(
max(CumulativeChargeableHrs)
FOR [year] in ('+#columnsCH+')
) as p
) as part2
ON part1.rn = part2.rn'
EXEC(#sql)
DROP TABLE #ChargeableYearDetails
DROP TABLE #tblyear
Output:
CumulativeHrsYY2012 CumulativeChargeableHrs2012 CumulativeHrsYY2013 CumulativeChargeableHrs2013 CumulativeHrsYY2014 CumulativeChargeableHrs2014 CumulativeHrsYY2015 CumulativeChargeableHrs2015 CumulativeHrsYY2016 CumulativeChargeableHrs2016
1657.75 1243.50 870.25 568.25 189.50 99.00 539.00 351.00 874.50 596.50
3925.50 3044.75 2517.75 1808.00 1982.75 1295.25 2542.75 1924.75 2721.50 2175.50

Using dynamic sql, something like this will work. Have changed your table var to temp tables. You will have to change it to accommodate for multiple rows. Just add a group by to the pivot. Pls refer this msdn blog post on how to pivot on multiple fields
DECLARE #cols AS NVARCHAR(MAX), #cols2 AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ',' + QUOTENAME('Cumulative Hours ' + cast(year as varchar(4)))
from #tblyear
group by year, id
order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols2 = STUFF((SELECT ',' + QUOTENAME('Cumulative Chargable Hours ' + cast(year as varchar(4)))
from #tblyear
group by year, id
order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
DECLARE #colsMax AS NVARCHAR(MAX), #cols2Max AS NVARCHAR(MAX)
select #colsMax = STUFF((SELECT ', MAX(' + QUOTENAME('Cumulative Hours ' + cast(year as varchar(4))) + ') ' + QUOTENAME('Cumulative Hours ' + cast(year as varchar(4)))
from #tblyear
group by year, id
order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #cols2Max = STUFF((SELECT ', MAX(' + QUOTENAME('Cumulative Chargable Hours ' + cast(year as varchar(4))) + ') ' + QUOTENAME('Cumulative Chargable Hours ' + cast(year as varchar(4)))
from #tblyear
group by year, id
order by id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = N'SELECT ' + #colsMax + ',' + #cols2Max + N' from
(
select CumulativeHrs, CumulativeChargeableHrs
, ''Cumulative Hours '' + cast(b.year as varchar(4)) as [CumHours]
, ''Cumulative Chargable Hours '' + cast(b.year as varchar(4)) as [CumChargableHours]
from #ChargeableYearDetails a join #tblyear b on a.year = b.id
) query
pivot
(
max(CumulativeHrs)
for CumHours in (' + #cols + N')
) p
pivot
(
max(CumulativeChargeableHrs)
for CumChargableHours in (' + #cols2 + N')
) p2
'
print #query
exec sp_executesql #query;

You can do this using dynamic sql.. this will create some MAX(CASE WHEN) statements for each year/hrs combo.. then execute the sql by using EXEC sp_executesql #sql or just EXEC(#sql)
DECLARE #Sql NVARCHAR(MAX),
#Cols NVARCHAR(MAX)
SELECT #Cols = COALESCE(#Cols + ', ', '') +
'MAX(CASE WHEN Year = ' + CAST(id AS VARCHAR) + ' THEN CumulativeHrs END) AS [Cumulative Hrs YTD - ' + CAST([year] AS VARCHAR) + '], ' +
'MAX(CASE WHEN Year = ' + CAST(id AS VARCHAR) + ' THEN CumulativeChargeableHrs END) AS [Cumulative Chargeable Hrs ' + CAST([year] AS VARCHAR) + '] '
FROM tblyear
ORDER BY [year] DESC
SET #Sql = 'SELECT ' + #Cols
+ ' FROM (SELECT *, Row_number() Over (Partition by [year] order by id) Rn FROM ChargeableYearDetails) t '
+ ' GROUP BY Rn'
EXEC sp_executesql #Sql
you won't be able to use table variables in this type of query without defining them as types first, but i'm guessing you're using actual tables.
Row_number was also added to break each record per year into separate rows

It is possible to use the PIVOT clause, but this has two disadvantages. Firstly, it can only pivot a single column. Secondly it can't handle dynamic columns; you have to pre-specify them.
In this example, I'm using two CTEs to pivot each column, then joining the result sets.
You might do better to implement this in a mid-tier layer programmed in C#.
WITH cteHrs AS
(
SELECT id, [1], [2], [3], [4], [5]
FROM
(SELECT id, [year], CumulativeHrs
FROM #ChargeableYearDetails) AS H
PIVOT
(
SUM(CumulativeHrs)
FOR [year] IN ([1], [2], [3], [4], [5])
) as pvtH
),
cteChgHrs AS
(
SELECT id, [1], [2], [3], [4], [5]
FROM
(SELECT id, [year], CumulativeChargeableHrs
FROM #ChargeableYearDetails) AS C
PIVOT
(
SUM(CumulativeChargeableHrs)
FOR [year] IN ([1], [2], [3], [4], [5])
) as pvtC
)
SELECT COALESCE(C.id, H.id) AS 'id',
C.[1] AS 'Cum Hrs 2012', H.[1] AS 'Cum Chg Hrs 2012',
C.[2] AS 'Cum Hrs 2013', H.[2] AS 'Cum Chg Hrs 2013',
C.[3] AS 'Cum Hrs 2014', H.[3] AS 'Cum Chg Hrs 2014',
C.[4] AS 'Cum Hrs 2015', H.[4] AS 'Cum Chg Hrs 2015',
C.[5] AS 'Cum Hrs 2016', H.[5] AS 'Cum Chg Hrs 2016'
FROM cteHrs AS H
FULL OUTER JOIN cteChgHrs AS C
ON C.id = H.id;
The result set is this.

Related

How Do I Join A SQL Pivot Query That Uses Delare Statements to a Normal SQL Query

Sorry if this isn't the best way to ask this but I am stuck at this point, I have tried researching but to no avail, trying to join these two queries:
SELECT [id]
,[title]
,[desc]
FROM [localTest].[dbo].[main];
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME([Year]) from [localTest].[dbo].[Years] FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT [ID], ' + #cols + ' from (select [ID], [Year], [Amount] FROM [localTest].[dbo].[Years] ) x pivot (min([Amount]) for [Year] in (' + #cols + ')) p '
execute(#query);
Looking for the final result here:
enter image description here
I figured it out, here is my solution:
DECLARE #cols AS NVARCHAR(MAX);
SELECT #cols = STUFF((SELECT distinct ',' + QUOTENAME([Year]) FROM [localTest].[dbo].[Years] FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'');
DECLARE #Sql VARCHAR(max);
SELECT #Sql = 'SELECT * FROM [localTest].[dbo].[main] a join (
SELECT * FROM (
SELECT [ID] id, [Year], [Amount]
FROM [localTest].[dbo].[Years]
) x pivot (
min([Amount])
for [Year] IN ('+#cols+')
) p ) as b on a.[ID] = b.id';
EXECUTE(#Sql);
Insert the result of second query to a #temp table and join the #temp table to main table like below:
SELECT [id]
,[title]
,[desc]
FROM [localTest].[dbo].[main];
DECLARE #cols AS NVARCHAR(MAX), #query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME([Year]) from [localTest].[dbo].[Years] FOR XML PATH(''),TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
set #query = 'SELECT [ID], ' + #cols + ' from (select [ID], [Year], [Amount] FROM [localTest].[dbo].[Years] ) x pivot (min([Amount]) for [Year] in (' + #cols + ')) p '
insert into #temp
execute(#query);
select * from [localTest].[dbo].[main] AS a inner join #temp as b on a.id = b.id

Data query using pivot encountered in SQL Server

I have a table with 3 nvarchar columns, 1 time column, and 2 columns Pass and Fail. I need to display the data by time column. On each milestone, there will be the number of Pass and Fail. I use Pivot and its only output Pass result without Fail. I tried everything. Please help
This is the input data:
Col1 Col2 Col3 Time Pass Fail
------------------------------------
A B C 08:30 80 0
A B C 09:30 60 2
A B C 10:30 80 0
A B C 11:30 70 0
I'm using this code:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT
#cols = STUFF((SELECT ',' + QUOTENAME(Time)
FROM Your_Table
GROUP BY Time
ORDER BY Time
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET #query = 'SELECT Col1,Col2,Col3,' + #cols + ' from
(
SELECT Col1,Col2,Col3,Time,Pass,Fail
from TD_SanLuong_CN
) x
pivot
(
sum(Pass)
for Time in (' + #cols + ')
) p1
pivot
(
sum(Fail)
for Time in (' + #cols + ')
) p2'
execute(#query);
Can I not use pivot to Fail?
I need output result:
Col1 Col2 Col3 08:30_Pass 08:30_Fail 09:30_Pass 09:30_Fail ...
A B C 80 0 60 2
Please help. Thank you!
Hi have a look at this code, i think this what you exactly needed as you expected Output
IF OBJECT_ID('tempdb..#Temp') IS NOT NULL
Drop table #Temp
CREATE TABLE #Temp (
Col1 CHAR(1),
Col2 CHAR(1),
Col3 CHAR(1),
[Time] TIME(0),
Pass INT,
Fail INT
);
INSERT #Temp (Col1, Col2, Col3, [Time], Pass, Fail) VALUES
('A', 'B', 'C', '08:30', 80, 0),
('A', 'B', 'C', '09:30', 60, 2),
('A', 'B', 'C', '10:30', 80, 0),
('A', 'B', 'C', '11:30', 70, 0);
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX),
#cols2 AS NVARCHAR(MAX),
#cols3 AS NVARCHAR(MAX),
#Dyncols AS NVARCHAR(MAX)
SELECT
#cols = STUFF((SELECT ',' + QUOTENAME(Time)
FROM #Temp
GROUP BY [Time]
ORDER BY [Time]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SELECT
#cols2 = STUFF((SELECT ',' + 'MAX('+QUOTENAME(Time)+')' +' As '+ '['+CAST((Time) AS VARCHAR)+'_Pass'+']'
FROM #Temp
GROUP BY [Time]
ORDER BY [Time]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SELECT
#cols3 = STUFF((SELECT ',' + 'MAX('+QUOTENAME(Time)+')' +' As '+ '['+CAST((Time) AS VARCHAR)+'_Fail'+']'
FROM #Temp
GROUP BY [Time]
ORDER BY [Time]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SELECT
#Dyncols = STUFF((SELECT ',' + '['+CAST((Time) AS VARCHAR)+'_Pass'+']'+','+'['+CAST((Time) AS VARCHAR)+'_Fail'+']'
FROM #Temp
GROUP BY [Time]
ORDER BY [Time]
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)'), 1, 1, '')
SET #query=';with cte
AS
(
SELECT Col1,Col2,Col3,'+#cols2+' From
(
SELECT Col1,Col2,Col3,Time,Pass,Fail
FROM #Temp
) AS X
PIVOT
(
SUM(Pass)
FOR [Time] IN ('+#cols+' )
) p1
Group by Col1,Col2,Col3
),Cte2
AS
(
SELECT '+#cols3+' From
(
SELECT Col1,Col2,Col3,Time,Pass,Fail
from #Temp
) x
PIVOT
(
SUM(Fail)
FOR Time IN ('+#cols+')
)p1
Group by Col1,Col2,Col3
)
SELECT Col1,Col2,Col3,'+#Dyncols+' FROM cte ,Cte2'
PRINT #query
EXEC(#query)
Result
Col1 Col2 Col3 08:30:00_Pass 08:30:00_Fail 09:30:00_Pass 09:30:00_Fail 10:30:00_Pass 10:30:00_Fail 11:30:00_Pass 11:30:00_Fail
A B C 80 0 60 2 80 0 70 0

Concatenate columns of multiple columns and multiple rows into one varchar value, when no of columns is dynamic

So i have this dynamic query that returns a result set having dynamic number of columns like so:
In this result set we have columns for ID, FacilityName and cycleNum will always be there but number of task columns can vary Task1, Task2, Task3..... upto Taskn.
The final result set I need is as follows:
For this i have tried this query:
Select distinct FacilityName,
substring(
(
Select ',' + a
From (SELECT ID, FacilityName, 'Cycle-'+ cast(CycleNum as varchar)+'::' + 'Task1~' + cast(Task1 as varchar) + ',Task2~' + cast(Task2 as varchar) + ',Task3~' + cast(Task3 as varchar) + ';' as a FROM #tempTable) ST1
Where ST1.FacilityName = ST2.FacilityName
ORDER BY ST1.FacilityName
For XML PATH ('')
), 2, 1000) CycleData
From (SELECT ID, FacilityName, 'Cycle-'+ cast(CycleNum as varchar)+'::' + 'Task1~' + cast(Task1 as varchar) + ',Task2~' + cast(Task2 as varchar) + ',Task3~' + cast(Task3 as varchar)+ ';' as a FROM #tempTable) ST2
This will work with following test data:
create table #tempTable
(
ID int,
FacilityName varchar(50),
CycleNum int,
Task1 datetime,
Task2 datetime,
Task3 datetime
)
Insert into #tempTable values
(1, 'A', 1, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(2, 'A', 2, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(3, 'B', 1, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126)),
(4, 'B', 2, convert(varchar(10), getdate(), 126), convert(varchar(10), dateadd(day,1,getdate()), 126), convert(varchar(10), dateadd(day,2,getdate()), 126))
But I cant think of any way to extend this to use dynamic columns. The list of all columns is saved in a master table so we can get comma-separated list of columns from there if needed.
Here is a dynamic way
Slightly different approach from your static query. To make it dynamic, Use while loop or CURSOR to generate the Task1 + Task2 + ..TaskN. Then use it in Select query.
DECLARE #columns VARCHAR(50)='Task1,Task2,Task3', -- Pass the list of column names
#int INT = 1,
#sql VARCHAR(8000)
SET #sql = ' ;WITH cte
AS (SELECT *,
''Cycle-'' + Cast(CycleNum AS VARCHAR(10)) + ''::'' '
WHILE #int <= Len(#columns) - Len(Replace(#columns, ',', '')) -- To find the number of Tasks in list
BEGIN
SET #sql += + '+''Task' + Cast(#int AS VARCHAR(10))
+ '~''+' + 'Cast(Task'
+ Cast(#int AS VARCHAR(10))
+ ' AS VARCHAR(50)) + '','''
SET #int += 1
END
SET #sql += ' AS concat_dates
FROM #tempTable)
SELECT DISTINCT FacilityName,
LEFT(CycleData, Len(CycleData) - 1)
FROM cte a
CROSS apply(SELECT b.concat_dates + '',''
FROM cte b
WHERE a.FacilityName = b.FacilityName
FOR xml path('''')) cs (CycleData)
'
--print #sql -- uncomment it to debug if you have any error when executing dynamic code
EXEC (#sql)
Not to worry about the usage of While Loop/CURSOR since we are not doing any resource intensive operations inside the loop.
Static Query will looking like this
;WITH cte
AS (SELECT *,
'Cycle-' + Cast(CycleNum AS VARCHAR(10))
+ '::' + 'Task1~' + Cast(Task1 AS VARCHAR(50))
+ ',' + 'Task2~' + Cast(Task2 AS VARCHAR(50))
+ ',' AS concat_dates
FROM #tempTable)
SELECT DISTINCT FacilityName,
LEFT(CycleData, Len(CycleData) - 1)
FROM cte a
CROSS apply(SELECT b.concat_dates + ','
FROM cte b
WHERE a.FacilityName = b.FacilityName
FOR xml path('')) cs (CycleData)
Use system tables. I prefer short and effective solutions :). This is guide, I'm sure you can finish it yourself with concentating strings (if you are not sure, add comment and I will add whole code or more description).
declare #columns varchar(max)
SELECT #columns = isnull(#columns + '+', '') + '''' + COLUMN_NAME + '~'' + Cast(' + COLUMN_NAME + ' as varchar(50))'
FROM tempdb.INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME like '#tempTable%'
AND c.COLUMN_NAME LIKE 'Task%' -- filter columns you are interested in
declare #sql varchar(4000) = 'select *, ' + #columns + ' from #tempTable'
print #sql
exec (#sql)

SQL Pivot Issue, Need dynamic column names

Alright. So we needed to get output as down with the code below. I got most of the code from: Convert Rows to columns using 'Pivot' in SQL Server. This gives me the dynamic column names for the years and then counts the events for each year. I need (or at least would like) for the column names to formatted as FY 2014 Total etc. instead of just 2014. So created another list of column names to be used as the output names. I figured that when doing the pivot you would be giving the custom names for the new columns. I'm not sure what I would need to do.
DECLARE #colValues as NVARCHAR(MAX),
#colNames as NVARCHAR(MAX),
#query as NVARCHAR(MAX)
--Creates the column names dynamically from the FY results
select #colValues = STUFF((
SELECT ',' + QUOTENAME(FY)
From [dbo].[Table]
Group By FY
Order By FY desc
for xml path(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
select #colNames = STUFF((
SELECT ',' + '[FY ' + Cast(FY as NVARCHAR(4)) + ' Total]'
From [dbo].[Table]
Group By FY
Order By FY desc
for xml path(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
--print(#cols)
--Creates the SQL Query using pivot with the dynamic columns
set #query = '
with temp1 as
(
Select a.EventType,
a.Days_Since_Last_Event,
row_number() over (partition by a.EventType order by a.Days_Since_Last_Event) as ranking
From
(
SELECT EventType
,DATEDIFF(day,EventDate,GETDATE()) AS Days_Since_Last_Event
FROM [dbo].[Table]
) a join
(
SELECT EventType
,DATEDIFF(day,EventDate,GETDATE()) AS Days_Since_Last_Event
FROM [dbo].[Table]
) b on a.EventType = b.EventType and a.Days_Since_Last_Event = b.Days_Since_Last_Event
), temp3 as
(
select EventType,
Days_Since_Last_Event
from temp1
where ranking = 1
), temp2 as
(
Select EventType
,'+ #colNames + '
From
(
Select EventType, FY, 1 as thing
From [dbo].[Table]
) a
Pivot
(
Count(thing)
for FY in (' + #colValues + ')
) b
)
Select t3.*, '+ #colNames +'
From temp3 t3
join temp2 t2 on t3.EventType = t2.EventType'
execute(#query);
use #colValues in your temp2 cte in both places.. then use this in your final select.
select #colNames = STUFF((
SELECT ',' + QUOTENAME(FY) + ' AS [FY ' + Cast(FY as NVARCHAR(4)) + ' Total]'
From [dbo].[Table]
Group By FY
Order By FY desc
for xml path(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
should give you something like this..
DECLARE #colValues as NVARCHAR(MAX),
#colNames as NVARCHAR(MAX),
#query as NVARCHAR(MAX)
--Creates the column names dynamically from the FY results
select #colValues = STUFF((
SELECT ',' + QUOTENAME(FY)
From [dbo].[Table]
Group By FY
Order By FY desc
for xml path(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
select #colNames = STUFF((
SELECT ',' + QUOTENAME(FY) + ' AS [FY ' + Cast(FY as NVARCHAR(4)) + ' Total]'
From [dbo].[Table]
Group By FY
Order By FY desc
for xml path(''), TYPE
).value('.', 'NVARCHAR(MAX)'),1,1,'')
--Creates the SQL Query using pivot with the dynamic columns
set #query = '
with temp1 as
(
Select a.EventType,
a.Days_Since_Last_Event,
row_number() over (partition by a.EventType order by a.Days_Since_Last_Event) as ranking
From
(
SELECT EventType
,DATEDIFF(day,EventDate,GETDATE()) AS Days_Since_Last_Event
FROM [dbo].[Table]
) a join
(
SELECT EventType
,DATEDIFF(day,EventDate,GETDATE()) AS Days_Since_Last_Event
FROM [dbo].[Table]
) b on a.EventType = b.EventType and a.Days_Since_Last_Event = b.Days_Since_Last_Event
), temp3 as
(
select EventType,
Days_Since_Last_Event
from temp1
where ranking = 1
), temp2 as
(
Select EventType
,'+ #colValues + '
From
(
Select EventType, FY, 1 as thing
From [dbo].[Table]
) a
Pivot
(
Count(thing)
for FY in (' + #colValues + ')
) b
)
Select t3.*, '+ #colNames +'
From temp3 t3
join temp2 t2 on t3.EventType = t2.EventType'
execute(#query);

How to sort or order date in dynamic Pivot Sql Server 2008

I have the following table
The table after pivoting is as follows. How do I maintain the date order in pivoted columns?
Here is how you can do it dynamically.
CREATE TABLE TEST
(
NAME VARCHAR(10),
DATECOL DATE,
VALUECol INT
)
INSERT INTO TEST
VALUES
('A', '01/JAN/2014', 10),
('B', '01/JAN/2014', 20),
('A', '26/JAN/2014', 20),
('B', '26/JAN/2014', 30),
('A', '01/FEB/2014', 40),
('B', '01/FEB/2014', 50),
('A', '26/FEB/2014', 60),
('B', '26/FEB/2014', 70)
DECLARE #colsPivot AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #colsPivot = STUFF((SELECT distinct ',' + QUOTENAME(DATECOL)
from TEST
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query
= 'select *
from
(
select NAME,DATECOL,VALUECOL
from TEST
) x1
pivot
(
max(VALUECOL)
for DATECOL in ('+ #colspivot +')
) p'
exec(#query)
Check this on SQL Fiddle
I got my own way to resolve this problem
CREATE TABLE #TEMP (Name varchar(10), [DATE] datetime, Value int)
INSERT #TEMP VALUES
('A','01/JAN/2014',10),
('B','01/JAN/2014',20),
('A','26/JAN/2014',20),
('B','26/JAN/2014',30),
('A','01/FEB/2014',40),
('B','01/FEB/2014',50),
('A','26/FEB/2014',60),
('B','26/FEB/2014',70)
Now we assign date in the format DD/MMM/YYYY to the variable
(Note: The [DATE] column should be of the type datetime/date)
DECLARE #cols NVARCHAR (MAX)
SELECT #cols = COALESCE (#cols + ',[' + REPLACE(CONVERT(NVARCHAR, [DATE], 106), ' ', '/') + ']',
'[' + REPLACE(CONVERT(NVARCHAR, [DATE], 106), ' ', '/') + ']')
FROM (SELECT DISTINCT [DATE] FROM #TEMP) PV
ORDER BY [DATE]
After pivot the columns will be in perfect Date order with the format DD/MMM/YYYY
DECLARE #query NVARCHAR(MAX)
SET #query = 'SELECT * FROM
(
SELECT Name,REPLACE(CONVERT(NVARCHAR, [DATE], 106), '' '', ''/'') [DATE] , value FROM #TEMP
) x
PIVOT
(
SUM(value)
FOR [DATE] IN (' + #cols + ')
) p;'
EXEC SP_EXECUTESQL #query
Like this you can convert to any date formats and can maintain the order of date in pivoted columns
by editing the conversion type in SELECT #cols and inner SELECT of Pivot statement

Resources