Monday, February 20, 2012

Pivot or Transpose a row

I would like to transpose/pivot a table that exists:

2 1 2 2 5
3 3 3 1 5
2 2 2 1 4
4 4 4 5 1
2 2 2 1 4
2 2 1 5 5

to:

1 1 2

1 2 3

1 3 2

1 4 4

1 5 2

1 6 2

2 1 1

2 2 3

2 3 2

2 4 4

2 5 2

2 6 2

Just looking at the first 6 rows of the new table:

Basically every column is copied to the third column of the new table.( 1,1) becomes (1,3)....(2,1) becomes (2,3)

There are 6 rows in the original table so the second column in the new table is a reoccuring count from 1 to 6. There is a value of 1 in the first column of the new table(first 6 rows).

The logic in the old table is: every column contains 6 answers from a particular user.

In the new table (1,1) represents the user, (1,2) represents the question, (1,3) represents the users answer for the question.

Is there a quick way to do this in Transact sql using a cursor and the and pivot function?

Any help would be appreciated!

There is not such concept as row number in SQL Server, so we will need a criteria to sort the table. Let us suppose that the table has a column with identity property, then we can use:

Code Snippet

create table dbo.t1 (

row_id int not null identity primary key,

c1 int,

c2 int,

c3 int,

c4 int,

c5 int

)

go

insert into dbo.t1(c1, c2, c3, c4, c5) values(2, 1, 2, 2, 5)

insert into dbo.t1(c1, c2, c3, c4, c5) values(3, 3, 3, 1, 5)

insert into dbo.t1(c1, c2, c3, c4, c5) values(2, 2, 2, 1, 4)

insert into dbo.t1(c1, c2, c3, c4, c5) values(4, 4, 4, 5, 1)

insert into dbo.t1(c1, c2, c3, c4, c5) values(2, 2, 2, 1, 4)

insert into dbo.t1(c1, c2, c3, c4, c5) values(2, 2, 1, 5, 5)

go

select

b.c1 as c_id,

a.row_id,

case b.c1

when 1 then a.c1

when 2 then a.c2

when 3 then a.c3

when 4 then a.c4

when 5 then a.c5

end as c3

from

dbo.t1 as a

cross join

(

select 1 as c1

union all

select 2 as c1

union all

select 3 as c1

union all

select 4 as c1

union all

select 5 as c1

) as b

order by

c_id,

a.row_id

go

-- SS 2005

select

c_id,

row_id,

val

from

(

select

row_id,

c1 as [1],

c2 as [2],

c3 as [3],

c4 as [4],

c5 as [5]

from

dbo.t1

) as pvt

unpivot

(val for c_id in ([1], [2], [3], [4], [5])) as unpvt

order by

c_id,

row_id

go

drop table dbo.t1

go

AMB

|||

Here is one way:

select n,
row_number() over ( partition by n order by current_timestamp ),
case n when 1 then c1
when 2 then c2
when 3 then c3
when 4 then c4
when 5 then c5
end
from tbl cross join
( select 1 union
select 2 union
select 3 union
select 4 union
select 5 ) D ( n )

Here tbl is your table and c1, c2, ... denotes the columns. The row_number() function is used to number the tables and the order by current_timestamp is simply a shortcut to generate the sequence without any reliance on existing columns.

--

Anith

|||

Hello

This works too:

SELECT IDENTITY(int, 1,1) AS ID_Num, t.*
INTO #TestResults
FROM TestResults t

CREATE TABLE dbo.NewResults (iUser INT, iQuestion INT, iAnswer INT)

DECLARE @.iColumns INT, @.lcSQL VARCHAR(200)
SET @.iColumns = 1

WHILE @.iColumns <= 5 -- Number of result columns in table TestResults
BEGIN
SET @.lcSQL = 'INSERT INTO dbo.NewResults (iUser, iQuestion, iAnswer) SELECT 1, ID_Num, c' + CAST(@.iColumns AS VARCHAR(2)) + ' FROM #TestResults'
EXEC(@.lcSQL)
SET @.iColumns = @.iColumns + 1
END

DROP TABLE #TestResults

SELECT * FROM dbo.NewResults

|||

Anith could you please explain the sql syntax?

over ( partition by n order by current_timestamp

and

D ( n )

thanks!

No comments:

Post a Comment