pivoting rows to columns in tsql - sql

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

Related

Dynamic Pivot SQL Server Not Showing Value

I have the following table:
oCode oDateTime oValue
---------------------------------------------
A 2017-01-01 10
B 2017-01-01 20
C 2017-01-01 5
I want to have the following result:
oDateTime A B C
------------------------------------------------
2017-01-01 10 20 5
If Static Pivot, I would use the following code:
select
*
from
(
select
sTag
, sDateTime
, sValue
from #condesarsp
) src
pivot
(
sum(sValue)
for sTag in ([X1], [X2], [X3])
) piv
order by sDateTime;
But unluckily, The oValue is not shown. Its just showing null value. Is there a typo on the code above?
After, I want to have dynamic pivot. So I don't need to define the column, It's just generate from oCode value.
Need help, thank you.
First, you would required to specify max() function rather than sum() and other sTag has value should be [A], [B], [C] rather than [X1]..[X3]
select *
from
(
select
oCode, oDateTime, oValue
from table
) src pivot(
max(oValue)
for ocode in ([A], [B], [C])
) piv
order by 1;
Ya there is some mistakes in your query. You have to give the oCode like A,B,C instead of [X1], [X2], [X3]. Like this:
for sTag in (A, B, C)
So the corrected code is:
select
*
from
(
select
oCode
, oDateTime
, oValue
from condesarsp
) src
pivot
(
sum(oValue)
for oCode in (A, B, C) -- This line is changed.
) piv
order by oDateTime;
Follow the link for demo:
http://sqlfiddle.com/#!18/06a9d/3
Dynamic Query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SET #cols = STUFF((SELECT distinct ',' + QUOTENAME(c.oCode)
FROM condesarsp c
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT oDateTime, ' + #cols + ' from
(
select oCode
,oDateTime
,oValue
from condesarsp
) x
pivot
(
sum(oValue)
for oCode in (' + #cols + ')
) p '
execute(#query);
Follow the link to the demo:
http://sqlfiddle.com/#!18/06a9d/7

converting and concatenating multiple rows into columns

I am using Dynamic PIVOT approach to convert the dynamic rows into columns and its working fine for me. But I have one more requirement on top of it. I am using below query:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT ','
+ QUOTENAME(case when d.col = 'STN_CODE' then col+'_'+cast(seq as varchar(10))
else col+'_'+cast(seq as varchar(10)) end)
from ( select row_number() over(partition by POF_FILE_ID,
PART_PFX,
PART_BASE,PART_SFX
order by STN_CODE,PROCESS_ELEMENT) seq
from APT_POINT_OF_FIT
) t
cross apply
(
select 'STN_CODE', 1 union all
select 'PROCESS_ELEMENT', 2
) d (col, so)
group by col, so, seq
order by seq, so
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT POF_FILE_ID,PART_PFX,PART_BASE,PART_SFX, ' +
#cols + '
from
(
select t.POF_FILE_ID,t.PART_PFX,t.PART_BASE,t.PART_SFX,
col = case
when c.col = ''STN_CODE'' then col+''_''+cast(seq as varchar(10))
else col+''_''+cast(seq as varchar(10))
end,
value
from
(
select POF_FILE_ID,PART_PFX,PART_BASE,PART_SFX,STN_CODE,
PROCESS_ELEMENT,
row_number() over(partition by POF_FILE_ID,
PART_PFX,
PART_BASE,
PART_SFX
order by STN_CODE) seq
from APT_POINT_OF_FIT
) t
cross apply
(
select ''STN_CODE'', STN_CODE union all
select ''PROCESS_ELEMENT'', PROCESS_ELEMENT
) c (col, value)
) x
pivot
(
max(value)
for col in (' + #cols + ')
) p '
execute sp_executesql #query;
My requirement is to insert the values in separate columns till seq 8 and concatenate all other column values coming after that seq(> seq8).
Any help would be appreciated.
Thanks!

Adding a WHERE statement refering another table in Dynamic SQL

I currently have the following script which is pivoting results from rows into columns. It works a Great, apart from two issues;
I have a flag in another table which I want to filter by (basically: WHERE Table.Stats=YES). I'd normally do this in a basic query with an inner join followed by that WHERE statement. In the query below, I already have a WHERE FileSeq=25, which works, but this criteria I need to get working is calling on a different table.
The query is returning a lot of uncessary NULL fields.
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
SELECT #cols = STUFF((SELECT ',' + QUOTENAME(col+CAST(rn AS varchar(6)))
FROM
(
SELECT row_number() over(partition by UID ORDER BY ClassCode) rn
FROM dbo.StudentClasses
) d
CROSS APPLY
(
SELECT 'ClassCode', 1
) c (col, so)
GROUP BY col, rn, so
ORDER BY rn, so
FOR XML PATH(''), TYPE
).VALUE('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT UID,' + #cols + '
FROM
(
SELECT UID, col+CAST(rn AS varchar(10)) col, VALUE
FROM
(
SELECT UID, classcode,
row_number() over(partition by UID ORDER BY classcode) rn
FROM StudentClasses WHERE FileSeq=25
) t
CROSS APPLY
(
SELECT ''classcode'', CAST(classcode AS varchar(6))
) c (col, VALUE)
) x
PIVOT
(
MAX(VALUE)
for col in (' + #cols + ')
) p '
EXECUTE(#query)
Any assistance appreciated

SQL Server 2008 CrossTab equivalent

Afternoon Guys n Girls.
Using SQL SERVER 2008.
I have a table called userModList. Its contains fields, "USERID"(int), "ModuleID"(int), and "Passed"(bin).
example data;
USERID ModuleID Passed
134 12 1
134 10 0
134 18 1
What i would like to display is:
USERID (moduleNum12) (ModuleNum10) (ModuleNum18)
134 1 0 1
Now In MS access all you would do is create a cross query, so User ID becomes the row, Module numbers become the Columns and Passed is the values (binary 1 or 0).
I would like to do this server Side in a Stored Procedure, but I have never Attempted cross tabbing data.
Also The moduleID is dynamic meaning there may be 3 modules for a user or 17. So it needs to be dynamic, not sure if this makes a big difference?
Anyway some help on this would be great, ill try and provide some sample code Of what I will try, But as it stands I'm stuck as to where to start.
many thanks guys!
There are a few different ways that you can do this in SQL Server you can use the PIVOT function:
select userid,
[12] moduleNum12,
[10] moduleNum10,
[18] moduleNum18
from
(
select userid, moduleid, cast(passed as int) passed
from yourtable
) d
pivot
(
max(passed)
for moduleId in ([12], [10], [18])
) piv;
See Demo
Or you can use an aggregate function with a CASE expression:
select userid,
max(case when moduleid = 12 then cast(passed as int) end) moduleNum12,
max(case when moduleid = 10 then cast(passed as int) end) moduleNum10,
max(case when moduleid = 18 then cast(passed as int) end) moduleNum18
from yourtable
group by userid;
See Demo.
The above work great if the values are known nut if you have unknown values, then you will need to use dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#colsAlias AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ',' + QUOTENAME(ModuleID)
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
select #colsAlias = STUFF((SELECT distinct ', ' + QUOTENAME(ModuleID) +' as moduleNum'+cast(ModuleID as varchar(10))
from yourtable
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT userid,' + #colsAlias + '
from
(
select userid, moduleid, cast(passed as int) passed
from yourtable
) d
pivot
(
max(passed)
for moduleid in (' + #cols + ')
) p '
execute(#query)
See Demo

SQL rotate rows to columns...dynamic number of rows [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
SQL Server dynamic PIVOT query?
I have a dataset that has the below structure.
CREATE TABLE #TempTable
(
Measure_ID INT,
measurement DECIMAL(18, 4)
)
INSERT INTO #TempTable
VALUES
(1,2.3)
,(1,3.4)
,(1,3.3)
,(2,3)
,(2,2.3)
,(2,4.0)
,(2,4.5)
I need to produce output that will look like this.
1,2.3,3.4,3.3
2,3,2.3,4.0,4.5
Basically its a pivot on Measure_ID. Unfortunately, there can be an unlimited number of measure_id's. So Pivot is out.
I'm hoping to avoid CURSORS, but will if that turns out to be the best approach.
If you have an unknown number of values, then you can use a PIVOT with dynamic SQL:
DECLARE #cols AS NVARCHAR(MAX),
#query AS NVARCHAR(MAX)
select #cols = STUFF((SELECT distinct ','
+ QUOTENAME('Measurement_' + cast(rn as varchar(10)))
from temptable
cross apply
(
select row_number() over(partition by measure_id order by measurement) rn
from temptable
) x
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set #query = 'SELECT measure_id, ' + #cols + ' from
(
select measure_id, measurement,
''Measurement_''
+ cast(row_number() over(partition by measure_id order by measurement) as varchar(10)) val
from temptable
) x
pivot
(
max(measurement)
for val in (' + #cols + ')
) p '
execute(#query)
See SQL Fiddle With Demo
If you have a known number of values, then you can hard-code the values, similar to this:
SELECT measure_id, [Measurement_1], [Measurement_2],
[Measurement_3], [Measurement_4]
from
(
select measure_id, measurement,
'Measurement_'
+ cast(row_number() over(partition by measure_id order by measurement) as varchar(10)) val
from temptable
) x
pivot
(
max(measurement)
for val in ([Measurement_1], [Measurement_2],
[Measurement_3], [Measurement_4])
) p
See SQL Fiddle With Demo
Both queries will produce the same results:
MEASURE_ID | MEASUREMENT_1 | MEASUREMENT_2 | MEASUREMENT_3 | MEASUREMENT_4
==========================================================================
1 | 2.3 | 3.3 | 3.4 | (null)
2 | 2.3 | 3 | 4 | 4.5