Pivoting a dynamic column based on split value - sql

I Have a couple of tables as per below
Position table
Id
PositionName
1
Developer
2
Analyst
3
Tester
Employee table
Id
Name
Positions
1
John
1,2
2
Lisa
3
3
Smith
1
4
Willow
NULL
5
Burly
2,3
From the above tables, what is the query to produce a pivoted report as per below?
Id
Name
Developer
Analyst
Tester
1
John
Y
Y
N
2
Lisa
N
N
Y
3
Smith
Y
N
N
4
Willow
N
N
N
5
Burly
N
Y
Y
I am stuck with the fact I have to do some split string and use the CASE WHEN to apply Y or N to the pivot.
here's my playground in SQL fiddle http://sqlfiddle.com/#!18/2ad8d/31

I'm having trouble getting Fiddle to work right now, but the code isn't too bad to just reproduce in full. Note that you should watch your #Cols variable to make sure all of your position names work as column names in real life, that's often not the case! Also note that your original example had duplicate employee IDs, I gave them unique values.
CREATE table Position (
Id int,
Name varchar(10)
);
insert into Position values
(1, 'Developer'),
(2, 'Analyist'),
(3, 'Tester');
CREATE table Employee (
Id int,
Name varchar(10),
Position varchar(MAX)
);
insert into Employee values
(1, 'John', '1,3'),
(2, 'Lisa', '3'),
(3, 'Smith', '1'),
(4, 'Willow', NULL),
(5, 'Burly', '2,3');
--This is your basic working PIVOT, we'll implement as a dynamic query once we're satisfied it works
;with cteEmp as (
SELECT E.Id as EID, E.Name as EName, P.Name as PName
, CASE WHEN CHARINDEX(CONVERT(nvarchar(10), P.Id)
, CONCAT(',', E.Position, ',') ) > 0 THEN 'Y' ELSE 'N' END as HasPos
FROM Employee as E CROSS JOIN Position as P
)SELECT Piv.* FROM cteEmp as E PIVOT (max(HasPos) FOR PName in (Developer, Analyist, Tester)) as Piv;
--To make it dynamic, build the list of positions from a query
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Name)
FROM Position
FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'with cteEmp as (
SELECT E.Id as EID, E.Name as EName, P.Name as PName
, CASE WHEN CHARINDEX(CONVERT(nvarchar(10), P.Id)
--, CONCAT('','', E.Position, '','') ) > 0 --Not 2008R2!
, '','' + E.Position + '','' ) > 0
THEN ''Y'' ELSE ''N'' END as HasPos
FROM Employee as E CROSS JOIN Position as P
)SELECT Piv.* FROM cteEmp as E PIVOT (max(HasPos)
FOR PName in (' + #cols + ') ) as Piv;'
execute(#query)
EDIT: Fixed the missing close parenthesis in the dynamic query.
EDIT: Note: This does not use a split function, it takes advantage of the facts that the ID must be an integer and the positions listed are delimited in a predictable way. We don't need a list of position IDs, we only need to know if the position ID in question is in the list. We prepend and append commas so we can search on ",1," and not just "1" because "1" would also match "21" but ",1," only matches the single ID.

You just need to join Position table to get the name of the position
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX);
SET #cols = STUFF((SELECT DISTINCT ',' + QUOTENAME(Name)
FROM Position
FOR XML PATH(''), TYPE ).value('text()[1]', 'NVARCHAR(MAX)')
,1,1,'');
set #query = N'
SELECT Name,' + #cols + N'
from
(
SELECT e.Name, p.PositionName
FROM Employee AS e
CROSS APPLY dbo.SplitString(Position, '','') AS ep(PositionId)
JOIN Position AS p ON p.Id = ep.PositionId
) x
pivot
(
COUNT(*)
FOR p.PositionName IN (' + #cols + N')
) p
';
exec sp_executesql #query;

Related

Dynamic SELECT statement, generate columns based on present and future values

Currently building a SELECT statement in SQL Server 2008 but would like to make this SELECT statement dynamic, so the columns can be defined based on values in a table. I heard about pivot table and cursors, but seems kind of hard to understand at my current level, here is the code;
DECLARE #date DATE = null
IF #date is null
set # date = GETDATE() as DATE
SELECT
Name,
value1,
value2,
value3,
value4
FROM ref_Table a
FULL OUTER JOIN (
SELECT
PK_ID ID,
sum(case when FK_ContainerType_ID = 1 then 1 else null) Box,
sum(case when FK_ContainerType_ID = 2 then 1 else null) Pallet,
sum(case when FK_ContainerType_ID = 3 then 1 else null) Bag,
sum(case when FK_ContainerType_ID = 4 then 1 else null) Drum
from
Packages
WHERE
#date between PackageStart AND PackageEnd
group by PK_ID ) b on a.Name = b.ID
where
Group = 0
The following works great for me , but PK_Type_ID and the name of the column(PackageNameX,..) are hard coded, I need to be dynamic and it can build itself based on present or futures values in the Package table.
Any help or guidance on the right direction would be greatly appreciated...,
As requested
ref_Table (PK_ID, Name)
1, John
2, Mary
3, Albert
4, Jane
Packages (PK_ID, FK_ref_Table_ID, FK_ContainerType_ID, PackageStartDate, PackageEndDate)
1 , 1, 4, 1JAN2014, 30JAN2014
2 , 2, 3, 1JAN2014, 30JAN2014
3 , 3, 2, 1JAN2014, 30JAN2014
4 , 4, 1, 1JAN2014, 30JAN2014
ContainerType (PK_ID, Type)
1, Box
2, Pallet
3, Bag
4, Drum
and the result should look like this;
Name Box Pallet Bag Drum
---------------------------------------
John 1
Mary 1
Albert 1
Jane 1
The following code like I said works great, the issue is the Container table is going to grow and I need to replicated the same report without hard coding the columns.
What you need to build is called a dynamic pivot. There are plenty of good references on Stack if you search out that term.
Here is a solution to your scenario:
IF OBJECT_ID('tempdb..##ref_Table') IS NOT NULL
DROP TABLE ##ref_Table
IF OBJECT_ID('tempdb..##Packages') IS NOT NULL
DROP TABLE ##Packages
IF OBJECT_ID('tempdb..##ContainerType') IS NOT NULL
DROP TABLE ##ContainerType
SET NOCOUNT ON
CREATE TABLE ##ref_Table (PK_ID INT, NAME NVARCHAR(50))
CREATE TABLE ##Packages (PK_ID INT, FK_ref_Table_ID INT, FK_ContainerType_ID INT, PackageStartDate DATE, PackageEndDate DATE)
CREATE TABLE ##ContainerType (PK_ID INT, [Type] NVARCHAR(50))
INSERT INTO ##ref_Table (PK_ID,NAME)
SELECT 1,'John' UNION
SELECT 2,'Mary' UNION
SELECT 3,'Albert' UNION
SELECT 4,'Jane'
INSERT INTO ##Packages (PK_ID, FK_ref_Table_ID, FK_ContainerType_ID, PackageStartDate, PackageEndDate)
SELECT 1,1,4,'2014-01-01','2014-01-30' UNION
SELECT 2,2,3,'2014-01-01','2014-01-30' UNION
SELECT 3,3,2,'2014-01-01','2014-01-30' UNION
SELECT 4,4,1,'2014-01-01','2014-01-30'
INSERT INTO ##ContainerType (PK_ID, [Type])
SELECT 1,'Box' UNION
SELECT 2,'Pallet' UNION
SELECT 3,'Bag' UNION
SELECT 4,'Drum'
DECLARE #DATE DATE, #PARAMDEF NVARCHAR(MAX), #COLS NVARCHAR(MAX), #SQL NVARCHAR(MAX)
SET #DATE = '2014-01-15'
SET #COLS = STUFF((SELECT DISTINCT ',' + QUOTENAME(T.[Type])
FROM ##ContainerType T
FOR XML PATH, TYPE).value('.', 'NVARCHAR(MAX)'),1,1,'')
SET #SQL = 'SELECT [Name], ' + #COLS + '
FROM (SELECT [Name], [Type], 1 AS Value
FROM ##ref_Table R
JOIN ##Packages P ON R.PK_ID = P.FK_ref_Table_ID
JOIN ##ContainerType T ON P.FK_ContainerType_ID = T.PK_ID
WHERE #DATE BETWEEN P.PackageStartDate AND P.PackageEndDate) X
PIVOT (COUNT(Value) FOR [Type] IN (' + #COLS + ')) P
'
PRINT #COLS
PRINT #SQL
SET #PARAMDEF = '#DATE DATE'
EXEC SP_EXECUTESQL #SQL, #PARAMDEF, #DATE=#DATE
Output:
Name Bag Box Drum Pallet
Albert 0 0 0 1
Jane 0 1 0 0
John 0 0 1 0
Mary 1 0 0 0
Static Query:
SELECT [Name],[Box],[Pallet],[Bag],[Drum] FROM
(
SELECT *
FROM
(
SELECT rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
) AS SourceTable
PIVOT
(
COUNT(PKID )
FOR [Type]
IN ( [Box],[Pallet],[Bag],[Drum])
) AS PivotTable
) AS Main
ORDER BY RFID
Dynamic Query:
DECLARE #columnList nvarchar (MAX)
DECLARE #pivotsql nvarchar (MAX)
SELECT #columnList = STUFF(
(
SELECT ',' + '[' + [Type] + ']'
FROM ContanerType
FOR XML PATH( '')
)
,1, 1,'' )
SET #pivotsql =
N'SELECT [Name],' + #columnList + ' FROM
(
SELECT *
FROM
(
SELECT rf.Name,cnt.[Type], pk.PK_ID AS PKID, rf.PK_ID AS RFID
FROM ref_Table rf INNER JOIN Packages pk ON rf.PK_ID = pk.FK_ref_Table_ID
INNER JOIN ContanerType cnt ON cnt.PK_ID = pk.FK_ContainerType_ID
) AS SourceTable
PIVOT
(
COUNT(PKID )
FOR [Type]
IN ( ' + #columnList + ')
) AS PivotTable
) AS Main
ORDER BY RFID;'
EXEC sp_executesql #pivotsql
Following my tutorial below will help you to understand the PIVOT functionality:
We write sql queries in order to get different result sets like full, partial, calculated, grouped, sorted etc from the database tables. However sometimes we have requirements that we have to rotate our tables. Sounds confusing?
Let's keep it simple and consider the following two screen grabs.
SQL Table:
Expected Results:
Wow, that's look like a lot of work! That is a combination of tricky sql, temporary tables, loops, aggregation......, blah blah blah
Don't worry let's keep it simple, stupid(KISS).
MS SQL Server 2005 and above has a function called PIVOT. It s very simple to use and powerful. With the help of this function we will be able to rotate sql tables and result sets.
Simple steps to make it happen:
Identify all the columns those will be part of the desired result set.
Find the column on which we will apply aggregation(sum,ave,max,min etc)
Identify the column which values will be the column header.
Specify the column values mentioned in step3 with comma separated and surrounded by square brackets.
So, if we now follow above four steps and extract information from the above sales table, it will be as below:
Year, Month, SalesAmount
SalesAmount
Month
[Jan],[Feb] ,[Mar] .... etc
We are nearly there if all the above steps made sense to you so far.
Now we have all the information we need. All we have to do now is to fill the below template with required information.
Template:
Our SQL query should look like below:
SELECT *
FROM
(
SELECT SalesYear, SalesMonth,Amount
FROM Sales
) AS SourceTable
PIVOT
(
SUM(Amount )
FOR SalesMonth
IN ( [Jan],[Feb] ,[Mar],
[Apr],[May],[Jun] ,[Jul],
[Aug],[Sep] ,[Oct],[Nov] ,[Dec])
) AS PivotTable;
In the above query we have hard coded the column names. Well it's not fun when you have to specify a number of columns.
However, there is a work arround as follows:
DECLARE #columnList nvarchar (MAX)
DECLARE #pivotsql nvarchar (MAX)
SELECT #columnList = STUFF(
(
SELECT ',' + '[' + SalesMonth + ']'
FROM Sales
GROUP BY SalesMonth
FOR XML PATH( '')
)
,1, 1,'' )
SET #pivotsql =
N'SELECT *
FROM
(
SELECT SalesYear, SalesMonth,Amount
FROM Sales
) AS SourceTable
PIVOT
(
SUM(Amount )
FOR SalesMonth
IN ( ' + #columnList +' )
) AS PivotTable;'
EXEC sp_executesql #pivotsql
Hopefully this tutorial will be a help to someone somewhere.
Enjoy coding.

Not able to formulate query to combine different row values in single row using pivot table

Below is the actual table
In the table above:
1) FEID is the examination ID which remains same for one exam, like ist semester examination of particular class. So it will remain same for all rows in above table as it consists of data of single exam always.
2) To store result of single student, marks for each subject are entered in each row. So if there are 5 subjects in a class,For each student marks of 5 subjects will be stored in 5 separate rows with marks obtained in each subject
3) Result, Result_code, NCHMCTID remain same in each row of single student. Like in above table, their values remain same in 3 rows.
Due to some reasons I cant remove this redundancy
So my question is, I need to store result of one student in single row, but number of rows related to single student to store each subject marks is not pre determined(number of subjects can change and determined dynamically)
So , if I have 5 subjects marks in 5 rows, I need those in single row.
Below is exactly what I need to convert above table into:
Above there are only 3 subjects, but they can be more than 3 subjects also.
To get subjects list, I use below query for the same and get subjects like:
[vb],[c(p)],VB(p) stored in single variable which I was trying to use in pivot table.
DECLARE #values varchar(max);
SET #values = '';
SELECT #values = #values +'['+ CAST(SubjectName AS varchar(max))+ ']' + ','
FROM tbSubjects where SubID IN(Select SubID from tbFinalMarks Where FEID=2) ;
SET #values = SUBSTRING(#values, 1, Len(#values) - 1)
Full procedure is below :
ALTER PROCEDURE [dbo].[prFinalMarksLoadByFEID]
#FEID int
AS
BEGIN
SET NOCOUNT ON;
DECLARE #values varchar(max);
SET #values = '';
SELECT #values = #values +'['+ CAST(SubjectName AS varchar(max))+ ']' + ','
FROM tbSubjects where SubID IN(Select SubID from tbFinalMarks Where FEID=2) ;
SET #values = SUBSTRING(#values, 1, Len(#values) - 1)
SELECT #values As 'Values'
select Student_Name,#values,Result,NCHMCTID,Examination_Name from
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
(SELECT dbo.tbStudent.Name AS Student_Name, dbo.tbSubjects.SubjectName AS Subject_Name, dbo.tbFinalMarks.MarksObtained AS Marks_Obtained,
dbo.tbFinalMarks.Result, dbo.tbFinalMarks.ResultCode AS Result_Code, ISNULL(dbo.tbStudent.NCHMCTID, 'Not Available') AS NCHMCTID,
dbo.tbFinalExam.ExaminationName as Examination_Name
FROM dbo.tbFinalMarks INNER JOIN
dbo.tbSubjects ON dbo.tbFinalMarks.SubID = dbo.tbSubjects.SubID INNER JOIN
dbo.tbStudent ON dbo.tbFinalMarks.StdID = dbo.tbStudent.StudentID INNER JOIN
dbo.tbFinalExam ON dbo.tbFinalMarks.FEID = dbo.tbFinalExam.FEID
Where FEID =#FEID
) ps
PIVOT
(
MAX(Marks_Obtained) For Subject_Name IN ([VB],[VB(P)],[C(P)])
) AS pvt
But I am not able to do it. Please help
Below part give me actual table which i need to manipulate for result table
(SELECT dbo.tbStudent.Name AS Student_Name, dbo.tbSubjects.SubjectName AS Subject_Name, dbo.tbFinalMarks.MarksObtained AS Marks_Obtained,
dbo.tbFinalMarks.Result, dbo.tbFinalMarks.ResultCode AS Result_Code, ISNULL(dbo.tbStudent.NCHMCTID, 'Not Available') AS NCHMCTID,
dbo.tbFinalExam.ExaminationName as Examination_Name
FROM dbo.tbFinalMarks INNER JOIN
dbo.tbSubjects ON dbo.tbFinalMarks.SubID = dbo.tbSubjects.SubID INNER JOIN
dbo.tbStudent ON dbo.tbFinalMarks.StdID = dbo.tbStudent.StudentID INNER JOIN
dbo.tbFinalExam ON dbo.tbFinalMarks.FEID = dbo.tbFinalExam.FEID
Where FEID =#FEID
)
I used [vb],[vb(p)],[C(P)] instead of #values ( it contains subjects list) as using # values in below part gives me error:
PIVOT
(
MAX(Marks_Obtained) For Subject_Name IN ([VB],[VB(P)],[C(P)])
) AS pvt
Below is the data:
FEID Student_Name Subject_Name Marks_Obtained Result Result_Code NCID Exam_Name
2 roof VB 100 First 1234 ist semester
2 roof VB(P) 100 First 1234 ist semester
2 roof C(P) 100 First 1234 ist semester
2 Amir VB 100 First nbb 8 ist semester
2 Amir VB(P) 100 First nbb 8 ist semester
2 Amir C(P) 100 First nbb 8 ist semester
Here's your query:
create table #t (FEID int, Student_Name char(4), Subject_Name char(5), Marks_Obtained int,
Result char(5), Result_Code int, NCID char(5), Exam_Name char(12))
go
insert #t values
( 2, 'roof', 'VB ', 100, 'First', NULL, '1234 ', 'ist semester'),
( 2, 'roof', 'VB(P)', 100, 'First', NULL, '1234 ', 'ist semester'),
( 2, 'roof', 'C(P) ', 100, 'First', NULL, '1234 ', 'ist semester'),
( 2, 'Amir', 'VB ', 100, 'First', NULL, 'nbb 8', 'ist semester'),
( 2, 'Amir', 'VB(P)', 100, 'First', NULL, 'nbb 8', 'ist semester'),
( 2, 'Amir', 'C(P) ', 100, 'First', NULL, 'nbb 8', 'ist semester')
go
declare #collist nvarchar(max)
SET #collist = stuff((select distinct ',' + QUOTENAME(subject_name)
FROM #t -- your table here
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #collist
declare #q nvarchar(max)
set #q = '
select *
from (
select
Student_Name, subject_name, Marks_Obtained, Exam_Name, Result, NCID, Result_Code
from (
select *
from #t -- your table here
) as x
) as source
pivot (
max(Marks_Obtained)
for subject_name in (' + #collist + ')
) as pvt
'
exec (#q)

Splitting a string of unlimited length SQL

I have a data column with values like this:
Table1
ID|GROUPNAME |MEMBER
1|GRP1_ML_Unit1_Role1|GRP=User1,DC=com;GRP=User2,DC=com
2|GRP2_ML_Unit2_Role2|GRP=User3,DC=com;GRP=User4,DC=com;GRP=User5,DC=com
3|GRP3_ML_Unit3_Role3|GRP=User6,DC=com;GRP=User7,DC=com;GRP=User8,DC=com;GRP=User8,DC=com
Expected output
ID|GRP1 |GRP2|GRP3 |GRP4 |MEM1 |MEM2 |MEM3 |MEM4|MEM5|
1 |GRP1 |ML |Unit1|Role1|GRP=User1,DC=com|GRP=User2,DC=com| | |
2 |GRP2 |ML |Unit2|Role2|GRP=User3,DC=com|GRP=User4,DC=com|GRP=User5,DC=com| |
3 |GRP3 |ML |Unit3|Role3|GRP=User6,DC=com|GRP=User7,DC=com|GRP=User8,DC=com|GRP=User8,DC=com |
Thanks,
Ryl
The completed solution is below with the sample data you gave me.
First, create a temp table and fill it with data.
-- Drop the table
drop table #member;
go
-- Sample table
create table #member
(
member_id int not null,
group_name varchar(256),
member_data varchar(8000)
);
go
-- Sample data
insert into #member values
(1, 'GRP1_ML_Unit1_Role1', 'GRP=User1,DC=com;GRP=User2,DC=com'),
(2, 'GRP2_ML_Unit2_Role2', 'GRP=User3,DC=com;GRP=User4,DC=com;GRP=User5,DC=com'),
(3, 'GRP3_ML_Unit3_Role3', 'GRP=User6,DC=com;GRP=User7,DC=com;GRP=User8,DC=com;GRP=User8,DC=com');
go
-- Show the data
select * from #member;
go
Second, copy down one of the many string splitters out there. I ended up installing Jeff Moden's string spliter for 8K max strings.
The query is almost there. However, each column we want is a row. We need to dynamically pivot the table.
--
-- Almost there!
--
-- Data in columns, instead of rows
select m.member_id, m.group_name, s.Item as cols_data, 'MEM' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data,';') s
go
Last but not least, figure out the number of columns. Write dynamic TSQL to pivot our dat and get our result.
--
-- Write dynamic sql to solve
--
DECLARE
#cols AS nvarchar(MAX),
#query AS nvarchar(MAX);
-- Get a dynamic number of columns
SET #cols = STUFF(
(
SELECT distinct ',' + QUOTENAME(c.cols_name)
FROM
(
select m.member_id, m.group_name, s.Item as cols_data, 'MEM' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data,';') s
) as c
FOR XML PATH(''), TYPE).value('.', 'NVARCHAR(MAX)')
,1,1,'');
print #cols;
-- Make dynamic pivot query
set #query = 'SELECT member_id as ID1, group_name as GROUP1, ' + #cols + ' from
(
select m.member_id, m.group_name, s.Item as cols_data, ''MEM'' + cast(s.ItemNumber as varchar(6)) as cols_name from #member as m
CROSS APPLY dbo.DelimitedSplit8k(m.member_data, '';'') s
) x
pivot
(
max(cols_data)
for cols_name in (' + #cols + ')
) p ';
execute(#query)
A screen shot of the results in the desired format.

pivoting rows to columns in tsql

I have the following table with the following sample data
ID Language Question SubQuestion SubSubQuestion TotalCount TotalPercent
3 E 9 0 1 88527 73%
3 E 9 0 2 19684 16%
3 E 9 0 3 12960 11%
3 E 9 0 9 933 1%
I want all in one row like this
ID Language TotalCount901 TotalPercent901 TotalCount902 TotalPercent902 TotalCount903 TotalPercent903
3 E 88527 73% 19684 16% 12960 11%
I've tired using the pivot command, but it dosnt to work for me.
I made a few assumptions based on your column names, but it looks like you want to use something similar to this. This applies both an UNPIVOT and then a PIVOT to get the values in the columns you requested:
select *
from
(
select id,
language,
col + cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)) col,
value
from
(
select id, language,
cast(TotalCount as varchar(10)) TotalCount,
totalPercent,
question, subquestion, SubSubQuestion
from yourtable
) usrc
unpivot
(
value
for col in (totalcount, totalpercent)
) un
) srcpiv
pivot
(
max(value)
for col in ([TotalCount901], [totalPercent901],
[TotalCount902], [totalPercent902],
[TotalCount903], [totalPercent903],
[TotalCount909], [totalPercent909])
) p
See SQL Fiddle with Demo
Note: when performing the UNPIVOT the columns need to be of the same datatype. If they are not, then you will need to convert/cast to get the datatypes the same.
If you have an unknown number of values to transform, you can use dynamic sql:
DECLARE #query AS NVARCHAR(MAX),
#colsPivot as NVARCHAR(MAX)
select #colsPivot
= STUFF((SELECT ','
+ QUOTENAME(c.name +
cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)))
from yourtable t
cross apply sys.columns as C
where C.object_id = object_id('yourtable') and
C.name in ('TotalCount', 'TotalPercent')
group by c.name, t.question, t.subquestion, t.subsubquestion
order by t.SubSubQuestion
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'select *
from
(
select id,
language,
col + cast(QUESTION as varchar(10))
+cast(subquestion as varchar(10))
+cast(SubSubQuestion as varchar(10)) col,
value
from
(
select id, language,
cast(TotalCount as varchar(10)) TotalCount,
totalPercent,
question, subquestion, SubSubQuestion
from yourtable
) usrc
unpivot
(
value
for col in (totalcount, totalpercent)
) un
) srcpiv
pivot
(
max(value)
for col in (' + #colsPivot + ')
) p '
execute(#query)
See SQL Fiddle with Demo

T:SQL: select values from rows as columns

I have a table for Profiles stores profile properties values in row style, ex:
[ProfileID] [PropertyDefinitionID] [PropertyValue]
1 6 Jone
1 7 Smith
1 8 Mr
1 3 50000
and another table for property definitions :
[PropertyDefinitionID] [PropertyName]
6 FirstName
7 LastName
8 Prefix
3 Salary
How to use PIVOT or any other way to show it in this way:
[ProfileID] [FirstName] [LastName] [Salary]
1 Jone Smith 5000
It's easy to do this without PIVOT keyword, just by grouping
select
P.ProfileID,
min(case when PD.PropertyName = 'FirstName' then P.PropertyValue else null end) as FirstName,
min(case when PD.PropertyName = 'LastName' then P.PropertyValue else null end) as LastName,
min(case when PD.PropertyName = 'Salary' then P.PropertyValue else null end) as Salary
from Profiles as P
left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
group by P.ProfileID
you can also do this with PIVOT keyword
select
*
from
(
select P.ProfileID, P.PropertyValue, PD.PropertyName
from Profiles as P
left outer join PropertyDefinitions as PD on PD.PropertyDefinitionID = P.PropertyDefinitionID
) as P
pivot
(
min(P.PropertyValue)
for P.PropertyName in ([FirstName], [LastName], [Salary])
) as PIV
UPDATE: For dynamic number of properties - take a look at Increment value in SQL SELECT statement
It looks like you might have an unknown number of PropertyName's that you need to turn into columns. If that is the case, then you can use dynamic sql to generate the result:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(PropertyName)
from propertydefinitions
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT profileid, ' + #cols + ' from
(
select p.profileid,
p.propertyvalue,
d.propertyname
from profiles p
left join propertydefinitions d
on p.PropertyDefinitionID = d.PropertyDefinitionID
) x
pivot
(
max(propertyvalue)
for propertyname in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle with Demo.