Dynamic pivot multiple columns - sql-server

I have a table with results like this:
EMP_ID | Boss_ID | Boss_Name | Specialty
1001 001 John sql
1001 001 John c#
1002 002 James c++
1002 003 Sarah sql
1002 003 Sarah python
1003 004 Jesse networking
Employees can have multiple bosses which can have multiple specialties.
I need to dynamically pivot the data so that I have one line per employee. I need to display the employee, all the bosses they have and just their line 1 specialty.
I am able to use dynamic pivot and display the multiple bosses part but I am unsure of how to display their specialty next to their name.
Here is what I have:
DECLARE #cols AS NVARCHAR(max)
,#query AS NVARCHAR(max)
select t.EMP_ID
,t.Boss_Name
,t.Boss_ID
,t.Specialty
,'BOSS' + '_' + cast(ROW_NUMBER() OVER (PARTITION BY t.EMP_ID ORDER BY t.BOSS_ID asc) AS VARCHAR) AS b_rn
,'SPEC' + '_' + cast(ROW_NUMBER() OVER (PARTITION BY t.Specialty ORDER BY t.BOSS_ID asc) AS VARCHAR) AS spec_rn
INTO #work
from #testing t
SELECT #cols = STUFF(
(SELECT DISTINCT TOP 100 PERCENT '],[' + w.b_rn
FROM #work w
ORDER BY '],[' + w.b_rn
FOR XML PATH('')
), 1, 2, ''
) + ']'
PRINT #cols
SET #query = N' SELECT EMP_ID,' + #cols + N'
INTO ##work_results FROM
(
SELECT EMP_ID
,Boss_Name
,b_rn
FROM #work
) AS sourcetable
PIVOT
(
max(Boss_Name) for b_rn IN ('+ #cols + N')
) AS pivot_table'
execute(#query)
select * from ##work_results
This gives me:
EMP_ID | BOSS_1 | BOSS_2 | BOSS_3
1001 John John NULL
1002 James Sarah Sarah
1003 Jesse NULL NULL
What I am really looking for is results like this:
EMP_ID | Boss_1 | Specialty_1 | Boss_2 | Specialty_1
1001 John sql
1002 James c++ Sarah sql
1003 Jesse networking
I have looked at other posts but they aren't quite what I am looking for.
Any help would be wonderful.
Thanks!

You might go this way:
The trick is, to concatenate your values. Therefore only one column, no problem with pivot...
DECLARE #tbl TABLE(EMP_ID INT,Boss_ID INT,Boss_Name VARCHAR(100),Specialty VARCHAR(100));
INSERT INTO #tbl VALUES
(1001,001,'John','sql')
,(1001,001,'John','c#')
,(1002,002,'James','c++')
,(1002,003,'Sarah','sql')
,(1002,003,'Sarah','python')
,(1003,004,'Jesse','networking');
SELECT p.*
FROM
(
SELECT tbl.EMP_ID
--If you need your Bosses in the given order you must add a sort crit to your original table!
,'Column_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.EMP_ID ORDER BY tbl.EMP_ID) AS VARCHAR(MAX)) AS ColumnName
,tbl.Boss_Name + ' (' + tbl.Specialty + ')' AS Concatenated
FROM #tbl AS tbl
) AS ToBePivoted
PIVOT
(
MIN(Concatenated) FOR ColumnName IN(Column_1,Column_2,Column_3 /*add maximum here*/)
) As p
The result
1001 John (sql) John (c#) NULL
1002 James (c++) Sarah (sql) Sarah (python)
1003 Jesse (networking) NULL NULL
If you need the values separated another trick is, to concatenate all needed columns in XML-format (but not XML-Type!).
As the concatenation is XML-Format it is quite easy to extract the elements just via their index.
DECLARE #tbl TABLE(EMP_ID INT,Boss_ID INT,Boss_Name VARCHAR(100),Specialty VARCHAR(100));
INSERT INTO #tbl VALUES
(1001,001,'John','sql')
,(1001,001,'John','c#')
,(1002,002,'James','c++')
,(1002,003,'Sarah','sql')
,(1002,003,'Sarah','python')
,(1003,004,'Jesse','networking');
SELECT p.EMP_ID
,CAST(Column_1 AS XML).value('x[1]','int') AS BossID_1
,CAST(Column_1 AS XML).value('x[2]','varchar(max)') AS BossName_1
,CAST(Column_1 AS XML).value('x[3]','varchar(max)') AS specialty_1
,CAST(Column_2 AS XML).value('x[1]','int') AS BossID_2
,CAST(Column_2 AS XML).value('x[2]','varchar(max)') AS BossName_2
,CAST(Column_2 AS XML).value('x[3]','varchar(max)') AS specialty_2
,CAST(Column_3 AS XML).value('x[1]','int') AS BossID_3
,CAST(Column_3 AS XML).value('x[2]','varchar(max)') AS BossName_3
,CAST(Column_3 AS XML).value('x[3]','varchar(max)') AS specialty_3
/*Add a maximum here*/
FROM
(
SELECT tbl.EMP_ID
--If you need your Bosses in the given order you must add a sort crit to your original table!
,'Column_' + CAST(ROW_NUMBER() OVER(PARTITION BY tbl.EMP_ID ORDER BY tbl.EMP_ID) AS VARCHAR(MAX)) AS ColumnName
,'<x>' + CAST(tbl.Boss_ID AS VARCHAR(10)) + '</x><x>' + tbl.Boss_Name + '</x><x>' + tbl.Specialty + '</x>' AS ValuesAsXML
FROM #tbl AS tbl
) AS ToBePivoted
PIVOT
(
MIN(ValuesAsXML) FOR ColumnName IN(Column_1,Column_2,Column_3 /*add maximum here*/)
) As p
The result
1001 1 John sql 1 John c# NULL NULL NULL
1002 2 James c++ 3 Sarah sql 3 Sarah python
1003 4 Jesse networking NULL NULL NULL NULL NULL NULL

Related

Sqlserver PIVOT to turn a "reconstruct" a flat table into columns - why does this not work?

The system we are using allows a data entry form to be created from multiple user defined fields to satisfy information required on a particular group of different "ORDES". The fields are then stored in a database as such from what is entered:
GUID OrderGUID UserDataCode Value
1 100 OrderName Breakfast
2 100 OrderDesc Food you eat before Lunch
3 100 CerealYN Y
4 100 ToastYN Y
5 100 ToastDesc White Bread
6 100 PaperYN Y
7 100 PaperDesc The Newsroom
8 101 OrderName Lunch
9 101 OrderDesc Food you eat before Dinner
10 101 CerealYN N
11 101 ToastYN Y
12 101 ToastDesc Brown Bread
13 101 PaperYN Y
14 101 PaperDesc The MiddayNews
(etc)
(in fact this is an Enterprise Hospital software but I have used simpler examples here)
I would like using SQL to return this table PIVOTed like below
OrderGUID OrderName OrderDESC CerealYN ToastYN ToastDesc ....
101 Breakfast Food you.. Y Y White Bread ....
102 Lunch Food you.. N Y Brown Bread ....
I wrote the following SQL based on examples found on the net:
DECLARE #DynamicPivotQuery AS NVARCHAR(MAX)
DECLARE #ColumnName AS NVARCHAR(MAX)
--Get distinct values of the PIVOT Column
SELECT #ColumnName= ISNULL(#ColumnName + ',','')
+ QUOTENAME([UserDataCode])
FROM (
SELECT
[UserDataCode]
FROM
[XXX].[dbo].[CV3OrderUserData]
WHERE OrderGUID = 3000680
) AS Codes;
--Prepare the PIVOT query using the dynamic
SET #DynamicPivotQuery = N'SELECT OrderGUID, ' + #ColumnName + '
FROM
[XXX].[dbo].[CV3OrderUserData]
PIVOT(Max(Value)
FOR UserDataCode IN (' + #ColumnName + ')) AS PVTTable'
--Execute the Dynamic Pivot Query
--SELECT #DynamicPivotQuery
EXEC sp_executesql #DynamicPivotQuery
However while it does the pivot as requested.. and puts the values in the correct new "dynamic" columns, if returns a row for each OrderGUID + Value,
ie:
OrderGUID OrderName OrderDesc CerealYN ToastYN
100 Breakfast null null null ...
100 null Food you.. null null ...
101 null null Y null ...
etc.etc
What am i doing wrong :( ?
The problem in your query is the pivot source query has GUID column which makes the pivot operator to consider GUID column.
To get the expected output you need to remove GUID column from the pivot source query.
Here is a static version you can convert it to dynamic version as you already did.
select * from
(
SELECT OrderGUID,UserDataCode,Value
FROM
tst) A
PIVOT(Max(Value)
FOR UserDataCode IN ([OrderName],[OrderDesc],
[CerealYN],[ToastYN],
[ToastDesc],[PaperYN],
[PaperDesc])) AS PVTTable
SQLFIDDLE DEMO

SQL Server Pivot Table with multiple column with dates

I have a PIVOT situation.
Source table columns:
Title Description Datetime RecordsCount
A California 2015-07-08 10:44:39.040 5
A California 2015-07-08 12:44:39.040 6
A California 2015-05-08 15:44:39.040 3
B Florida 2015-07-08 16:44:39.040 2
B Florida 2015-05-08 19:44:39.040 4
Now I need this pivoted as
2015-07-08 2015-05-08
Title Description
A California 11 3
B Florida 2 4
if we have two record counts on same dates (no matter of time) then sum them, else display in different column.
Trying to write something like this, but it throws errors.
Select * from #DataQualTest
PIVOT (SUM(RecordCount) FOR DateTime IN (Select Datetime from #DataQualTest) )
AS Pivot_Table
Please help me out with this.
Thanks
Not exactly the word for word solution but this should give you a direction.
create table #tmp
(
country varchar(max)
, date1 datetime
, record int
)
insert into #tmp values ('California', '2010-01-01', 2)
insert into #tmp values ('California', '2010-01-01', 5)
insert into #tmp values ('California', '2012-01-01', 1)
insert into #tmp values ('Florida', '2010-01-01', 3)
insert into #tmp values ('Florida', '2010-01-01', 5)
select * from #tmp
pivot (sum(record) for date1 in ([2010-01-01], [2012-01-01])) as avg
output
country 2010-01-01 2012-01-01
California 7 1
Florida 8 NULL
If you want to be more flexible, you need some pre-processing to get from full timestamps to days (in order for later on the PIVOT's grouping to actually have the anticipated effect):
CREATE VIEW DataQualTestView AS
SELECT
title
, description
, DATEFROMPARTS (DATEPART(yyyy, date_time),
DATEPART(mm, date_time),
DATEPART(dd, date_time)) AS day_from_date_time
, recordsCount
FROM DataQualTest
;
From there you could continue:
DECLARE #query AS NVARCHAR(MAX)
DECLARE #columns AS NVARCHAR(MAX)
SELECT #columns = ISNULL(#columns + ',' , '')
+ QUOTENAME(day_from_date_time)
FROM (SELECT DISTINCT
day_from_date_time
FROM DataQualTestView) AS TheDays
SET #query =
N'SELECT
title
, description
, ' + #columns + '
FROM DataQualTestView
PIVOT(SUM(recordsCount)
FOR day_from_date_time IN (' + #columns + ')) AS Pivoted'
EXEC SP_EXECUTESQL #query
GO
... and would get:
| title | description | 2015-05-08 | 2015-07-08 |
|-------|-------------|------------|------------|
| A | California | 3 | 11 |
| B | Florida | 4 | 2 |
See it in action: SQL Fiddle.
Please comment, if and as this requires adjustment / further detail.

How to retrieve multiple detail records plus the master record as a single row?

I have two tables with a structure similar to this:
Person:
ID Name Age
1 Jack 25
2 Jill 23
Tests:
ID PersonID TestID Result
1 1 1 125
2 1 2 120
3 1 3 75
4 2 1 90
5 2 2 95
6 2 3 7.2
Is there a way to retrieve that data with a single statement in a way that each record in the master table is presented in a single row? Something like this:
PersonID Name Age Test1 Test2 Test3
1 Jack 25 125 120 75
2 Jill 23 90 95 7.2
So far, the only way I have come up with has been to create a function which iterates through the detail records and fills a temporary table. Not very elegant.
Thanks in advance
In order to get this result, you will need to use the PIVOT function. This transforms the data from multiple rows into columns.
If you know the values ahead of time or you will have a limited number of TestId values, then you can hard-code the query making the query static.
SELECT Name,
Age,
[1] AS Test1,
[2] AS Test2,
[3] AS Test3
FROM
(
SELECT P.Name, P.Age, t.TestID, t.Result
FROM tests t
INNER JOIN person P
ON p.ID = t.PersonID
) T
PIVOT
(
sum(Result)
FOR TestID IN ([1], [2], [3])
) piv;
See SQL Fiddle with Demo.
But if you have an unknown number of TestId values, then you will want to use dynamic SQL to generate the list of columns at run-time. You Code will be:
DECLARE #cols AS NVARCHAR(MAX),
#colNames AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(testId)
from tests
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colNames = STUFF((SELECT distinct ',' + QUOTENAME(testId) +' as Test'+cast(testId as varchar(10))
from tests
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT Name, age, ' + #colnames + ' from
(
select P.Name, P.Age, t.TestID, t.Result
from tests t
inner join person P
on p.ID = t.PersonID
) x
pivot
(
sum(Result)
for TestID in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo.
They both will generate the same result, difference being that the dynamic one will increase/decrease the columns if the number of test ids changes:
| NAME | AGE | TEST1 | TEST2 | TEST3 |
--------------------------------------
| Jack | 25 | 125 | 120 | 75 |
| Jill | 23 | 90 | 95 | 7.2 |
You can do a pivot on the TestID
Here you go... its kinda messy but you can improve on it :)
SELECT Name,Age,SUM([1]) AS Test1,SUM([2]) AS Test2,SUM([3]) AS Test3
FROM(
SELECT P.Name,P.Age,Te.ID, TestID,Result
FROM Test Te
INNER JOIN dbo.Person P ON P.ID=Te.PersonID) T
PIVOT(MAX(T.Result) FOR TestID IN([1],[2],[3])) AS pvt
GROUP BY Name,Age
heres some links
http://msdn.microsoft.com/en-us/library/ms177410(v=sql.105).aspx
http://www.codeproject.com/Questions/393632/How-to-use-Pivot-in-SQL
http://blog.sqlauthority.com/2008/06/07/sql-server-pivot-and-unpivot-table-examples/

Create query with dynamic columns from different tables

I'm trying to create a query with dynamic columns, based on data from three tables.
This is the database structure:
STUDENT
studentID int,
studentNumber int,
studentName nvarchar(100).
EXAM:
examID int,
examName varchar(100),
examenDate datetime,
EXAM_REGISTRATION:
studentID int,
examID int,
A record is added to the EXAM_REGISTRATION table when a student has registered for an exam.
What I'm trying to get is a list of all the exams and all the students in a pivot table to see which students have registered for which exams, like this:
Quite frankly I don't know where to start.
I can query everything individually and put it all together but how can I combine it into one query?
I've been researching pivot tables, but every example seems to query only from one table and uses numbers and functions like MIN, AVG etc.
Can someone help me along?
ok lets go
some data to play with
create table #student
(studentID int, studentNumber int, studentName nvarchar(100))
create table #exam
(examID int, examName nvarchar(100), examDate datetime)
create table #examReg
(studentID int, examID int)
insert into #student
values (1, 787878, 'pierwszy')
,(2, 89898, 'drugi')
,(3, 343434, 'trzeci')
,(4, 121212, 'czwarty')
insert into #exam
values (1, 'exPierwszy', GETDATE())
,(2, 'exDrugi', GETDATE())
,(3, 'exTrzeci', GETDATE())
insert into #examReg
values (1,2),(1,3)
, (2,2),(2,3)
,(3,1),(3,2)
,(4,1),(4,2),(4,3)
and now the main part, and explanation
first of all you have to get pivot query
select examName, examDate , min([1]) , min([2]), min([3]) ,min([4])--studentID as studentID, examDate --,studentNumber
from
(select a.studentID , studentNumber, examDate, examName
from #student a
join #examReg b on a.studentID = b.studentID
join #exam c on c.examID = b.examID ) as m
pivot
(min(studentNumber) FOR studentID in ([1],[2],[3],[4])) as t
group by examName, examDate
as you have it , just change it select statement and studentID list in pivot declaration, you have to generate those parts dynamicly , so we just copy previously written query and replace columns with our token
declare #sqlTemplate nvarchar(max) =
'select examName, examDate ##sqlColumnList##
from
(select a.studentID , studentNumber, examDate, examName
from #student a
join #examReg b on a.studentID = b.studentID
join #exam c on c.examID = b.examID ) as m
pivot
(min(studentNumber) FOR studentID in (##sqlStudentIDList##)) as t
group by examName, examDate
'
after that you generate column list and studentID list by concatenting strings in tsql
declare #sqlColumnList nvarchar(max) = ''
select #sqlColumnList += ',min([' + cast(studentID as nvarchar(10)) + ']) as [' + studentName +'(' + cast(studentNumber as nvarchar(10)) + ')]'
from #student
declare #sqlStudentIDList nvarchar(max) = ''
select #sqlStudentIDList += '[' + CAST(studentID as nvarchar(10)) + '],'
from #student
set #sqlStudentIDList = SUBSTRING(#sqlStudentIDList, 0, LEN(#sqlStudentIDList))
select #sqlStudentIDList
once you have it , all you have to do is to replace tokens in previous template
set #sqlTemplate = REPLACE(#sqlTemplate, '##sqlColumnList##', #sqlColumnList)
set #sqlTemplate = REPLACE(#sqlTemplate, '##sqlStudentIDList##', #sqlStudentIDList)
select #sqlTemplate
exec sp_executesql #sqlTemplate
and thats it
if you want to read more about pivot go for msdn
if you want to read about dynamic go for this link
edit: to adjust the query for the question from comment you would have to change #sqlColumnList like that
select #sqlColumnList += ',min(' + QUOTENAME(studentID) + ') as Student' + CAST(studentID as nvarchar(10)) + '_REG,
'''+ studentName + ''' as Student' + cast(studentID as nvarchar(10)) + '_NAME,
'+ cast(studentID as nvarchar(10)) + ' as Student' + cast(studentID as nvarchar(10)) + '_ID'
from #student
This is a pivot of the data. I would perform this slightly different than the other answer. If you know all of the values, then you can hard-code the values.
A static version will be:
select examname,
examendate,
IsNull([Smith, John (14323)], 'false') [Smith, John (14323)],
IsNull([Craft, Peter (14334)], 'false') [Craft, Peter (14334)],
IsNull([Davis, Alan (13432)], 'false') [Davis, Alan (13432)],
IsNull([Newman, Ted (133123)], 'false') [Newman, Ted (133123)]
from
(
select e.examname,
e.examenDate,
s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')' studentNameNum,
'true ' as Flag
from exam e
left join exam_registration er
on e.examid = er.examid
right join student s
on er.studentid = s.studentid
) src
pivot
(
max(flag)
for studentNameNum in ([Smith, John (14323)], [Craft, Peter (14334)],
[Davis, Alan (13432)], [Newman, Ted (133123)])
) piv
See SQL Fiddle with Demo
If your values are unknown then the query will be:
DECLARE #cols AS NVARCHAR(MAX),
#colsNull AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')')
from student s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsNull = STUFF((SELECT distinct ',IsNull(' + QUOTENAME(s.studentName + ' ('+cast(s.studentnumber as varchar(50))+')')+', ''false'')'+' as '+QUOTENAME(s.studentName+' ('+cast(s.studentnumber as varchar(50))+')')
from student s
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT examname,
examenDate,' + #colsNull + ' from
(
select e.examname,
e.examenDate,
s.studentName + '' (''+cast(s.studentnumber as varchar(50))+'')'' studentNameNum,
''true '' as Flag
from exam e
left join exam_registration er
on e.examid = er.examid
right join student s
on er.studentid = s.studentid
) x
pivot
(
max(flag)
for studentNameNum in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo
The result will be:
| EXAMNAME | EXAMENDATE | CRAFT, PETER (14334) | DAVIS, ALAN (13432) | NEWMAN, TED (133123) | SMITH, JOHN (14323) |
----------------------------------------------------------------------------------------------------------------------------
| Exam 1 | 2013-01-01 12:00:00 | false | false | true | false |
| Exam 2 | 2013-01-01 14:00:00 | true | false | false | true |
| Exam 3 | 2013-01-02 12:00:00 | true | true | false | false |
| Exam 4 | 2013-01-02 14:00:00 | false | false | true | false |
| Exam 5 | 2013-01-03 12:00:00 | false | false | false | true |

SQL Server Pivots: Displaying row values to column headers

I have a table (items) which is in the following format:
ITEMNO | WEEKNO | VALUE
A1234 | 1 | 805
A2345 | 2 | 14.50
A3547 | 2 | 1396.70
A2208 | 1 | 17.65
A4326 | 6 | 19.99
It's a table which shows the value of sales for items in a given week.
The results or what I want to display in a table format is the item number in a row followed by columns for each week containing the values, e.g.
ITEMNO | WK1 | WK2 | WK3 | WK4 | WK5 ...etc up to 52
A1234 | 805 | 345 | 234 | 12 | 10 ...etc up to 52
A2345 | 23 | 12 | 456 | 34 | 99 ...etc up to 52
A3456 | 234 | 123 | 34 | 25 | 190 ...etc up to 52
Although I've 52...so I've only data for up to week9 but that will increase with time.
So basically what it is I'm looking to display is the week number value as a column header.
Is this possible...although I'm tempted to just grab the data and display properly through code/(asp.net) but I was wondering if there was away to display it like this in SQL?
Does anyone know or think that that this might be the best way?
There are two ways of doing this with static SQL and dynamic SQL:
Static Pivot:
SELECT P.ItemNo, IsNull(P.[1], 0) as Wk1, IsNull(P.[2], 0) as Wk2
, IsNull(P.[3], 0) as Wk3, IsNull(P.[4], 0) as Wk4
, IsNull(P.[5], 0) as Wk5, IsNull(P.[6], 0) as Wk6
, IsNull(P.[7], 0) as Wk7, IsNull(P.[8], 0) as Wk8
, IsNull(P.[9], 0) as Wk9
FROM
(
SELECT ItemNo, WeekNo, [Value]
FROM dbo.Items
) I
PIVOT
(
SUM([Value])
FOR WeekNo IN ([1], [2], [3], [4], [5], [6], [7], [8], [9])
) as P
Dynamic Pivot:
DECLARE
#cols AS NVARCHAR(MAX),
#y AS INT,
#sql AS NVARCHAR(MAX);
-- Construct the column list for the IN clause
SET #cols = STUFF(
(SELECT N',' + QUOTENAME(w) AS [text()]
FROM (SELECT DISTINCT WeekNo AS W FROM dbo.Items) AS W
ORDER BY W
FOR XML PATH('')),
1, 1, N'');
-- Construct the full T-SQL statement
-- and execute dynamically
SET #sql = N'SELECT *
FROM (SELECT ItemNo, WeekNo, Value
FROM dbo.Items) AS I
PIVOT(SUM(Value) FOR WeekNo IN(' + #cols + N')) AS P;';
EXEC sp_executesql #sql;
GO
Maybe something like this:
Test data
CREATE TABLE #tbl
(
ITEMNO VARCHAR(100),
WEEKNO INT,
VALUE FLOAT
)
INSERT INTO #tbl
VALUES
('A1234',1,805),
('A2345',2,14.50),
('A3547',2,1396.70),
('A2208',1,17.65),
('A4326',6,19.99)
Week columns
DECLARE #cols VARCHAR(MAX)
;WITH Nbrs ( n ) AS (
SELECT 1 UNION ALL
SELECT 1 + n FROM Nbrs WHERE n < 52 )
SELECT #cols = COALESCE(#cols + ','+QUOTENAME('WK'+CAST(n AS VARCHAR(2))),
QUOTENAME('WK'+CAST(n AS VARCHAR(2))))
FROM
Nbrs
Just the included weeks
DECLARE #cols VARCHAR(MAX)
;WITH CTE
AS
(
SELECT
ROW_NUMBER() OVER(PARTITION BY WEEKNO ORDER BY WEEKNO) AS RowNbr,
WEEKNO
FROM
#tbl
)
SELECT #cols = COALESCE(#cols + ','+QUOTENAME('WK'+CAST(WEEKNO AS VARCHAR(2))),
QUOTENAME('WK'+CAST(WEEKNO AS VARCHAR(2))))
FROM
CTE
WHERE
CTE.RowNbr=1
Dynamic pivot
DECLARE #query NVARCHAR(4000)=
N'SELECT
*
FROM
(
SELECT
tbl.ITEMNO,
''WK''+CAST(tbl.WEEKNO AS VARCHAR(2)) AS WEEKNO,
tbl.VALUE
FROM
#tbl as tbl
) AS p
PIVOT
(
SUM(VALUE)
FOR WEEKNO IN ('+#cols+')
) AS pvt'
EXECUTE(#query)
Drop the temp table
DROP TABLE #tbl
Use Pivot, although quite a bit of code..
If you create report in reporting services, can use matrix..
Follow the below walkthrogh which explains it clearly
http://www.tsqltutorials.com/pivot.php
You can use PIVOT if you want to do this in sql directly.
It can be more efficient to use the SQL Server to do this as opposed to the client depending upon the size of the data and the aggregation.

Resources