문제

I have a dynamically generated table that I need to have all the columns changed into rows

so my table looks like this

Conv1 | Conv2 | ...
data1 | data2 | ...
data1 | data2 | ...
data1 | data2 | ...
 ...  |  ...  | ...

because it's dynamic I don't know exactly how many rows/columns there are without running Select count(*) or something like that.

basically I want the above table to be changed to this

data1 | data1 | data1 | ...
data2 | data2 | data2 | ...
data3 | data3 | data3 | ...
data4 | data4 | data4 | ...

I looked at using Pivot however I'm not sure how I would use it in this case.

I am working with SQL Server 2008 R2

Any help will be greatly appreciated. Let me know if you need any more information.

Thank you.

--Update

here's the current table structure with the "Conv" items as the column names.

Conv1 | Conv2 | Conv3 | ...
data1 | data2 | data3 | ...
data1 | data2 | data3 | ...
data1 | data2 | data3 | ...
 ...  |  ...  |  ...  | ...

where the "data" pieces are varchar(250)

consider the data a repository of conversations (Conv1) and the rows are a series of questions and responses. because of the nature of what I'm having to work with I have no idea which "data" content is a question and which is a response.

this is what I want the results to look like:

        Col1  | Col2  | Col3  | ...
Conv1 | data1 | data1 | data1 | ...
Conv2 | data2 | data2 | data2 | ...
Conv3 | data3 | data3 | data3 | ...
Conv4 | data4 | data4 | data4 | ...

If this is still not enough information let me know and I'll see what else I can provide.

도움이 되었습니까?

해결책

What you are trying to do is a full data transpose where your current columns of data become rows and your rows become columns, this can be accomplished in two steps. First, applying the UNPIVOT function to convert your current columns of Conv1, Conv2, etc into rows, then you apply the PIVOT function to convert the data1, data2 into columns.

Prior to trying to write a dynamic version of the query, I would always start with a static version so can get the correct logic, then convert to dynamic sql. In order to generate your new column names Col1, Col2, etc I would use a windowing function like row_number() when querying your data, this will generate a unique sequence for each row of data that you want to transpose.

The UNPIVOT code will be similar to:

;with cte as
(
    select Conv1, Conv2, Conv3,
        row_number() over(order by conv1) seq
    from dbo.yourtable
)
select * 
from 
(
    select Conv, value, 
        col = 'Col'+cast(seq as varchar(50))
    from cte
    unpivot
    (
        value for Conv in (Conv1, Conv2, Conv3)
    ) unpiv
) src;

See SQL Fiddle with Demo. The data will look like:

|  CONV | VALUE |  COL |
|-------|-------|------|
| Conv1 | data1 | Col1 |
| Conv2 | data2 | Col1 |
| Conv3 | data3 | Col1 |
| Conv1 | data1 | Col2 |
| Conv2 | data2 | Col2 |
| Conv3 | data3 | Col2 |

You'll notice that you now have multiple rows for each Conv1 and you have a new column with that uses the row_number() to create your new column names. Now you can use PIVOT to finish the rotation of the data:

;with cte as
(
    select Conv1, Conv2, Conv3,
        row_number() over(order by conv1) seq
    from dbo.yourtable
)
select Conv, Col1, Col2, Col3
from 
(
    select Conv, value, 
        col = 'Col'+cast(seq as varchar(50))
    from cte
    unpivot
    (
        value for Conv in (Conv1, Conv2, Conv3)
    ) unpiv
) src
pivot
(
    max(value)
    for col in (Col1, Col2, Col3)
) piv;

See SQL Fiddle with Demo. This will fully transpose your current data to your final result. For your case you stated you need a dynamic solution so you will need to use dynamic SQL. This will involve getting a list of the column names that need to be unpivoted and then the new columns for the pivot:

DECLARE @colsUnpivot AS NVARCHAR(MAX),
    @colsPivot AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @colsUnpivot = STUFF((SELECT ','+ quotename(c.name)
                    from sys.tables t
                    inner join sys.columns c
                        on t.object_id = c.object_id
                    where t.name = 'yourtable'
                    group by c.name, c.column_id
                    order by c.column_id
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

select @colsPivot = STUFF((SELECT ','+ quotename('Col'+cast(seq as varchar(10)))
                   from
                   (
                    select row_number() over(order by conv1) seq
                    from dbo.yourtable
                   ) d
                   group by seq
                   order by seq
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query 
  = ';with cte as
    (
        select Conv1, Conv2, Conv3,
            row_number() over(order by conv1) seq
        from dbo.yourtable
    )
    select Conv, '+@colsPivot+'
    from 
    (
        select Conv, value, 
            col = ''Col''+cast(seq as varchar(50))
        from cte
        unpivot
        (
            value for Conv in ('+@colsUnpivot+')
        ) unpiv
    ) src
    pivot
    (
        max(value)
        for col in ('+@colsPivot+')
    ) piv'

execute sp_executesql @query;

See SQL Fiddle with Demo. Both give a final result of:

|  CONV |  COL1 |  COL2 |  COL3 |
|-------|-------|-------|-------|
| Conv1 | data1 | data1 | data1 |
| Conv2 | data2 | data2 | data2 |
| Conv3 | data3 | data3 | data3 |
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top