如何在SQLServer中将多行数据转换为列数据

如何在SQLServer中将多行数据转换为列数据,sql,sql-server,pivot,unpivot,Sql,Sql Server,Pivot,Unpivot,我的sql查询得到以下结果: Id atr1 atr2 atr3 atr4 1 a bsdf csdfs djk 5 esdds f gds hkkj 8 i j ksd lk 9 ads sdf dfse

我的sql查询得到以下结果:

Id         atr1       atr2       atr3       atr4

1          a          bsdf       csdfs      djk
5          esdds      f          gds        hkkj
8          i          j          ksd        lk
9          ads        sdf        dfse       wer  
现在我需要以下格式的上述结果:

S.no   1        2         3      4
Id     1        5         8      9
atr1   a        esdds     i      ads 
atr2   bsdf     f         j      sdf 
atr3   csdfs    gds       ksd    dfse
atr4   djk      hkkj      lk     wer

我无法使用Pivot和Unpivot执行此操作。

为了获得您想要的最终结果,您需要取消当前列的Pivot,然后应用Pivot函数。但在您取消pivot/pivot数据之前,我建议使用row_number为每一行生成一个唯一的值

有几种不同的方法可以获得结果,包括使用带有CASE表达式的聚合函数、静态透视和动态透视

使用大小写聚合:首先使用UNION ALL查询将多个列转换为行,然后使用带有大小写表达式的聚合函数来获得结果:

;with cte as
(
  select id, atr1, atr2, atr3, atr4,
    row_number() over(order by id) seq
  from yourtable
) 
select s_no,
  max(case when seq = 1 then value end) [1],
  max(case when seq = 2 then value end) [2],
  max(case when seq = 3 then value end) [3],
  max(case when seq = 4 then value end) [4]
from
(
  select seq, s_no = 'id', value = cast(id as varchar(5)), so = 1
  from cte
  union all
  select seq, s_no = 'atr1', value = atr1, so = 2
  from cte
  union all
  select seq, s_no = 'atr2', value = atr2, so = 3
  from cte
  union all
  select seq, s_no = 'atr3', value = atr3, so = 4
  from cte
  union all
  select seq, s_no = 'atr4', value = atr4, so = 5
  from cte
) d
group by s_no, so
order by so;

静态UNPIVOT/PIVOT:如果要转换的值数量有限,则可以硬编码查询。unpivot的过程将转换多个列id、atr1、atr2、atr3和atr4,并将它们转换为多行。您没有指定正在使用的SQL Server版本,但可以使用UNPIVOT函数或交叉应用来完成此操作

看。我使用交叉应用和UNIONALL来选择每个列并将它们转换为多行。此查询将您的数据转换为以下格式:

| SEQ | S_NO | VALUE | SO |
|   1 |   id |     1 |  1 |
|   1 | atr1 |     a |  2 |
|   1 | atr2 |  bsdf |  3 |
|   1 | atr3 | csdfs |  4 |
|   1 | atr4 |   djk |  5 |
|   2 |   id |     5 |  1 |
将数据放入多行后,可以应用PIVOT函数:

select s_no, [1], [2], [3], [4]
from
(
  select seq, s_no, value, so
  from
  (
    select id, atr1, atr2, atr3, atr4,
      row_number() over(order by id) seq
    from yourtable
  ) s
  cross apply
  (
    select 'id', cast(id as varchar(5)), 1 union all
    select 'atr1', atr1, 2 union all
    select 'atr2', atr2, 3 union all
    select 'atr3', atr3, 4 union all
    select 'atr4', atr4, 5
  ) c (s_no, value, so)
) d
pivot
(
  max(value)
  for seq in ([1], [2], [3], [4])
) piv
order by so;

动态UNPIVOT/PIVOT:如果要创建的新列的数量已知或有限,但要转换为列的值的数量未知,则上述方法非常有效,您将需要考虑使用动态SQL。这将生成一个sql字符串,然后执行该字符串以获得最终结果:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(seq) 
                    from 
                    (
                      select row_number() over(order by id) seq
                      from yourtable
                    )d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT s_no,' + @cols + ' 
            from
            (
              select seq, s_no, value, so
              from
              (
                select id, atr1, atr2, atr3, atr4,
                  row_number() over(order by id) seq
                from yourtable
              ) s
              cross apply
              (
                select ''id'', cast(id as varchar(5)), 1 union all
                select ''atr1'', atr1, 2 union all
                select ''atr2'', atr2, 3 union all
                select ''atr3'', atr3, 4 union all
                select ''atr4'', atr4, 5
              ) c (s_no, value, so)
            ) x
            pivot 
            (
                max(value)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;
看。所有版本将给出一个结果:

| S_NO |     1 |     2 |   3 |    4 |
|   id |     1 |     5 |   8 |    9 |
| atr1 |     a | esdds |   i |  ads |
| atr2 |  bsdf |     f |   j |  sdf |
| atr3 | csdfs |   gds | ksd | dfse |
| atr4 |   djk |  hkkj |  lk |  wer |

为了得到您想要的最终结果,您需要取消当前列的pivot,然后应用pivot函数。但在您取消pivot/pivot数据之前,我建议使用row_number为每一行生成一个唯一的值

有几种不同的方法可以获得结果,包括使用带有CASE表达式的聚合函数、静态透视和动态透视

使用大小写聚合:首先使用UNION ALL查询将多个列转换为行,然后使用带有大小写表达式的聚合函数来获得结果:

;with cte as
(
  select id, atr1, atr2, atr3, atr4,
    row_number() over(order by id) seq
  from yourtable
) 
select s_no,
  max(case when seq = 1 then value end) [1],
  max(case when seq = 2 then value end) [2],
  max(case when seq = 3 then value end) [3],
  max(case when seq = 4 then value end) [4]
from
(
  select seq, s_no = 'id', value = cast(id as varchar(5)), so = 1
  from cte
  union all
  select seq, s_no = 'atr1', value = atr1, so = 2
  from cte
  union all
  select seq, s_no = 'atr2', value = atr2, so = 3
  from cte
  union all
  select seq, s_no = 'atr3', value = atr3, so = 4
  from cte
  union all
  select seq, s_no = 'atr4', value = atr4, so = 5
  from cte
) d
group by s_no, so
order by so;

静态UNPIVOT/PIVOT:如果要转换的值数量有限,则可以硬编码查询。unpivot的过程将转换多个列id、atr1、atr2、atr3和atr4,并将它们转换为多行。您没有指定正在使用的SQL Server版本,但可以使用UNPIVOT函数或交叉应用来完成此操作

看。我使用交叉应用和UNIONALL来选择每个列并将它们转换为多行。此查询将您的数据转换为以下格式:

| SEQ | S_NO | VALUE | SO |
|   1 |   id |     1 |  1 |
|   1 | atr1 |     a |  2 |
|   1 | atr2 |  bsdf |  3 |
|   1 | atr3 | csdfs |  4 |
|   1 | atr4 |   djk |  5 |
|   2 |   id |     5 |  1 |
将数据放入多行后,可以应用PIVOT函数:

select s_no, [1], [2], [3], [4]
from
(
  select seq, s_no, value, so
  from
  (
    select id, atr1, atr2, atr3, atr4,
      row_number() over(order by id) seq
    from yourtable
  ) s
  cross apply
  (
    select 'id', cast(id as varchar(5)), 1 union all
    select 'atr1', atr1, 2 union all
    select 'atr2', atr2, 3 union all
    select 'atr3', atr3, 4 union all
    select 'atr4', atr4, 5
  ) c (s_no, value, so)
) d
pivot
(
  max(value)
  for seq in ([1], [2], [3], [4])
) piv
order by so;

动态UNPIVOT/PIVOT:如果要创建的新列的数量已知或有限,但要转换为列的值的数量未知,则上述方法非常有效,您将需要考虑使用动态SQL。这将生成一个sql字符串,然后执行该字符串以获得最终结果:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT ',' + QUOTENAME(seq) 
                    from 
                    (
                      select row_number() over(order by id) seq
                      from yourtable
                    )d
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT s_no,' + @cols + ' 
            from
            (
              select seq, s_no, value, so
              from
              (
                select id, atr1, atr2, atr3, atr4,
                  row_number() over(order by id) seq
                from yourtable
              ) s
              cross apply
              (
                select ''id'', cast(id as varchar(5)), 1 union all
                select ''atr1'', atr1, 2 union all
                select ''atr2'', atr2, 3 union all
                select ''atr3'', atr3, 4 union all
                select ''atr4'', atr4, 5
              ) c (s_no, value, so)
            ) x
            pivot 
            (
                max(value)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;
看。所有版本将给出一个结果:

| S_NO |     1 |     2 |   3 |    4 |
|   id |     1 |     5 |   8 |    9 |
| atr1 |     a | esdds |   i |  ads |
| atr2 |  bsdf |     f |   j |  sdf |
| atr3 | csdfs |   gds | ksd | dfse |
| atr4 |   djk |  hkkj |  lk |  wer |

这么多类似的帖子在网上。。。。检查提供1758个答案已经出现在SO上-先看看这些…我没有固定的行数。SO上有这么多类似的帖子。。。。检查已提供1758个答案,请先看这些答案…我没有固定的行数。你是天才。向你致敬-你是天才。向你致敬-