如何将行数据作为列查询?

Rac*_*hel 7 sql t-sql pivot sql-server-2005

我确定我在这里遗漏了一些东西.

我有这样的数据集:

FK    RowNumber    Value    Type    Status
1     1            aaaaa    A       New
1     2            bbbbb    B       Good
1     3            ccccc    A       Bad
1     4            ddddd    C       Good
1     5            eeeee    B       Good
2     1            fffff    C       Bad
2     2            ggggg    A       New
2     3            hhhhh    C       Bad
3     1            iiiii    A       Good
3     2            jjjjj    A       Good

我想查询前3个结果并将它们作为列进行透视,因此最终结果集如下所示:

FK    Value1    Type1    Status1    Value2    Type2    Status2    Value3    Type3    Status3
1     aaaaa     A        New        bbbbb     B        Good       ccccc     A        Bad
2     fffff     C        Bad        ggggg     A        New        hhhhh     C        Bad
3     iiiii     A        Good       jjjjj     A        Good

如何在SQL Server 2005中完成此操作?

我一直在尝试使用PIVOT,但我仍然对该关键字非常不熟悉,无法按照我想要的方式工作.

SELECT * --Id, [1], [2], [3]
FROM
(
    SELECT Id, Value, Type, Status
    , ROW_NUMBER() OVER (PARTITION BY Id ORDER Status, Type) as [RowNumber]
    FROM MyTable
) as T
PIVOT
(
    -- I know this section doesn't work. I'm still trying to figure out PIVOT
    MAX(T.Value) FOR RowNumber IN ([1], [2], [3]),
    MAX(T.Type) FOR RowNumber IN ([1], [2], [3]),
    MAX(T.Status) FOR RowNumber IN ([1], [2], [3])
) AS PivotTable;
Run Code Online (Sandbox Code Playgroud)

我的实际数据集比这更复杂,我需要前10条记录,而不是前3条,所以我不想简单地CASE WHEN RowNumber = X THEN...为每一条记录做.

更新

我测试了所有的答案下面,发现大部分人似乎对与较小的数据集没有明显的性能差异(3K左右的记录)一样,对大型数据集运行查询时,却出现了一个细微的差别.

以下是我使用80,000条记录并查询前10行中5列的测试结果,因此我的最终结果集为50列+ Id列.我建议你自己测试一下,以决定哪一种最适合你和你的环境.

  • bluefoot的解析和重新转动数据的平均速度最快,大约12秒.我也很喜欢这个答案,因为我觉得最容易阅读和维护.

  • Aaron的回答koderoid的答案都建议使用a MAX(CASE WHEN RowNumber = X THEN ...),并且在13秒左右的时间内落后于平均值.

  • 罗德尼使用多个PIVOT语句的答案平均大约16秒,尽管PIVOT语句较少可能会更快(我的测试有5个).

  • Aaron的答案的前半部分建议使用CTE并且OUTER APPLY是最慢的.我不知道需要多长时间运行,因为我2分钟后取消它,那就是与3K左右的记录,3行3列,而不是80K的记录,10行,5列.

Rod*_*ams 7

您可以尝试在三个单独的pivot语句中执行pivot.请尝试一下:

SELECT Id
    ,MAX(S1) [Status 1]
    ,MAX(T1) [Type1]
    ,MAX(V1) [Value1]
    --, Add other columns
FROM
(
    SELECT Id, Value , Type, Status
    , 'S' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Status_RowNumber]
    , 'T' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Type_RowNumber]
    , 'V' + CAST(ROW_NUMBER() OVER (PARTITION BY Id ORDER BY Status, Type) AS VARCHAR(10)) [Value_RowNumber]
    FROM MyTable
) as T
PIVOT
(   
    MAX(Status) FOR Status_RowNumber IN ([S1], [S2], [S3],[S4],[S5],[S6],[S7],[S8],[S9],[S10])
)AS StatusPivot
PIVOT(
    MAX(Type) FOR Type_RowNumber IN ([T1], [T2], [T3],[T4],[T5],[T6],[T7],[T8],[T9],[T10])
)AS Type_Pivot
PIVOT(
    MAX(Value) FOR Value_RowNumber IN ([V1], [V2], [V3],[V4],[V5],[V6],[V7],[V8],[V9],[V10])
)AS Value_Pivot
GROUP BY Id
Run Code Online (Sandbox Code Playgroud)

我不知道选择前十条记录的标准的全部范围,但这会产生和输出,可能会让您更接近您的答案.

SQL小提琴示例

  • +1,非常聪明.但请不要长度使用`VARCHAR`.http://sqlblog.com/blogs/aaron_bertrand/archive/2009/10/09/bad-habits-to-kick-declaring-varchar-without-length.aspx (3认同)

Tar*_*ryn 7

你可以做一个UNPIVOT然后一个PIVOT数据.这可以静态地或动态地完成:

静态版本:

select *
from
(
  select fk, col + cast(rownumber as varchar(1)) new_col,
    val
  from 
  (
    select fk, rownumber, value, cast(type as varchar(10)) type,
      status
    from yourtable
  ) x
  unpivot
  (
    val
    for col in (value, type, status)
  ) u
) x1
pivot
(
  max(val)
  for new_col in
    ([value1], [type1], [status1], 
     [value2], [type2], [status2],
    [value3], [type3])
) p
Run Code Online (Sandbox Code Playgroud)

看看SQL Fiddle with demo

动态版本,这将获取列的列表,unpivot然后pivot在运行时:

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

select @colsUnpivot = stuff((select ','+quotename(C.name)
         from sys.columns as C
         where C.object_id = object_id('yourtable') and
               C.name not in ('fk', 'rownumber')
         for xml path('')), 1, 1, '')

select @colsPivot = STUFF((SELECT  ',' 
                      + quotename(c.name 
                         + cast(t.rownumber as varchar(10)))
                    from yourtable t
                     cross apply 
                      sys.columns as C
                   where C.object_id = object_id('yourtable') and
                         C.name not in ('fk', 'rownumber')
                   group by c.name, t.rownumber
                   order by t.rownumber
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')


set @query 
  = 'select *
      from
      (
        select fk, col + cast(rownumber as varchar(10)) new_col,
          val
        from 
        (
          select fk, rownumber, value, cast(type as varchar(10)) type,
            status
          from yourtable
        ) x
        unpivot
        (
          val
          for col in ('+ @colsunpivot +')
        ) u
      ) x1
      pivot
      (
        max(val)
        for new_col in
          ('+ @colspivot +')
      ) p'

exec(@query)
Run Code Online (Sandbox Code Playgroud)

看看SQL Fiddle with Demo

两者都会生成相同的结果,但如果您不提前知道列数,则动态效果很好.

动态版本在假设rownumber已经是数据集的一部分的情况下工作.

  • @Lamak我正准备参加我的婚礼. (3认同)