Monday, February 20, 2012

Pivot Example when you don't know the exact values to Pivot on


Say, I have the following temporary table (@.tbl) where the QuestionID field will change values over time

Survey QuestionID Answer
1 1 1
1 2 0
2 1 1
2 2 2

I'd like to perform a pivot on it like this: select * from @.tbl Pivot (min(Answer) for QuestionID in ([1], [2])) as PivotTable

...however, I can't just name the [1], [2] values because they're going to change.

Instead of naming the values like this:
for QuestionID in ([1], [2], [3], [4])

I tried something like this:
for QuestionID in (select distinct QuestionID from @.tbl)

but am getting a syntax error. Is it possible to set up a pivot like this:
select * from @.tbl Pivot (min(Answer) for Question_CID in (select distinct @.QuestionID from @.tbl)) as PivotTable

or does anyone know another way to do it?

You cannot use a subquery in the IN for your pivot. I wish we could. Here is a dynamic solution:

Code Snippet

Create Table #tb1 (

Survey int,

QuestionID int,

Answer int

);

--Survey QuestionID Answer

--1 1 1

--1 2 0

--2 1 1

--2 2 2

--Sample Data

Insert Into #tb1 Values('1','1', '1');

Insert Into #tb1 Values('1','2', '0');

Insert Into #tb1 Values('2','1', '1');

Insert Into #tb1 Values('2','2', '2');

Insert Into #tb1 Values('3','3', '1');

--SELECT DISTINCT QuestionID FROM #tb1

SET

NOCOUNT ON

DECLARE

@.T AS TABLE(y nvarchar(20) NOT NULL PRIMARY KEY)

INSERT

INTO @.T SELECT DISTINCT QuestionID FROM #tb1

DECLARE

@.T1 AS TABLE(num int NOT NULL PRIMARY KEY)

DECLARE @.i AS int

SET @.i=1

WHILE @.i <20

BEGIN

INSERT INTO @.T1 SELECT @.i

SET @.i=@.i+1

END

DECLARE @.cols AS nvarchar(MAX), @.cols2 AS nvarchar(MAX),@.y AS nvarchar(20)

SET @.y = (SELECT MIN(y) FROM @.T)

SET @.cols = N''

SET @.cols2 = N''

WHILE @.y IS NOT NULL

BEGIN

SET @.cols = @.cols + N',['+CAST(@.y AS nvarchar(20))+N']'

SET @.cols2 = @.cols2 + N'+ coalesce(['+CAST(@.y AS nvarchar(20))+N'],'''')'

SET @.y = (SELECT MIN(y) FROM @.T WHERE y > @.y)

END

SET @.cols = SUBSTRING(@.cols, 2, LEN(@.cols))

SET @.cols2 = SUBSTRING(@.cols2, 2, LEN(@.cols2)-1)

DECLARE @.sql AS nvarchar(MAX)

SET @.sql = N'SELECT Survey, ' +@.cols + N' FROM (SELECT Survey, QuestionID, Answer FROM #tb1) as t

PIVOT (Min(Answer) FOR QuestionID IN(' + @.cols + N')) AS pvt'

EXEC sp_executesql @.sql

print @.sql

drop table #tb1

|||

Try:

Code Snippet

use tempdb

go

create table #t1 (

survey int,

questionid int,

answer int

)

insert into #t1 values(1,1, 1)

insert into #t1 values(1,2, 0)

insert into #t1 values(2,1, 1)

insert into #t1 values(2,2, 2)

insert into #t1 values(0,0, 1)

declare @.cols nvarchar(max)

declare @.sql nvarchar(max)

set @.cols = stuff(

(

select ',' + quotename(QuestionID)

from (select distinct QuestionID from #t1) as t

order by QuestionID

for xml path('')

), 1, 1, '')

set @.sql = N'

select

Survey, ' + @.cols + N'

from

#t1

pivot

(

min(Answer)

for QuestionID in (' + @.cols + N')

) as pvt

'

exec sp_executesql @.sql

drop table #t1

go

In case you do not want to see the NULL values, take a look to this post. There I posted a similar solution.

http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2123214&SiteID=1

Be careful with SQL Injection.

PIVOT on Steroids

http://www.sqlmag.com/Article/ArticleID/94268/sql_server_94268.html

AMB

No comments:

Post a Comment