数据透视表缺少列

时间:2013-10-31 19:36:33

标签: sql sql-server tsql pivot unpivot

我正在尝试使用数据透视表以diff格式获取信息。

这是我的表:

    CREATE TABLE yourtable
([case] int, [category] varchar(4))
    ;

    INSERT INTO yourtable
([case], [category])
    VALUES
(1, 'xx'),
(1, 'xyx'),
(1, 'abc'),
(2, 'ghj'),
(2, 'asdf'),
(3, 'dfgh')
    ; 

这是我的支点命令由bluefeet提供:

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

    select @cols = STUFF((SELECT distinct ',' + QUOTENAME('cat'+cast(seq as    
    varchar(10))) 
                from
                (
                  select row_number() over(partition by [case] 
                                           order by category) seq
                  from yourtable
                ) d
        FOR XML PATH(''), TYPE
        ).value('.', 'NVARCHAR(MAX)') 
    ,1,1,'')

    set @query = 'SELECT [case],' + @cols + ' 
        from 
        (
          SELECT [case], category,
            ''cat''+
              cast(row_number() over(partition by [case] 
                                     order by category) as varchar(10)) seq
          FROM yourTable
        ) x
        pivot 
        (
            max(category)
            for seq in (' + @cols + ')
        ) p '

    execute sp_executesql @query;

输出很好,它是我需要的格式。

CASE    CAT1    CAT2    CAT3
1        abc    xx    xyx
2        asdf   ghj   (null)
3        dfgh   (null)   (null)

但是,我还需要在表中添加其他列。修改后的表格如下,但我不知道如何将其添加到QUOTENAME。

    CREATE TABLE yourtable
    ([case] int, [category] varchar(4), [status] varchar(4))
    ;

    INSERT INTO yourtable
    ([case], [category], [status])
    VALUES
    (1, 'xx', '00'),
    (1, 'xyx', '01'),
    (1, 'abc', '00'),
    (2, 'ghj', '01'),
    (2, 'asdf', '00'),
    (3, 'dfgh', '01')
     ; 

如何做到这一点?我应该添加额外的QUOTENAME命令吗?结果应该是:

    CASE    CAT1    status1    CAT2      status2      CAT3      status3
    1       abc     00         xx          00         xyx        01
    2       asdf    00         ghj         01       (null)    (null)
    3       dfgh    01        (null)     (null)     (null)    (null)

1 个答案:

答案 0 :(得分:4)

由于您现在有两个想要PIVOT的列,因此您可以先将categorystatus列取消隐藏到包含多行的单个列中。

您可以通过几种不同的方式取消数据,您可以使用UNPIVOT或CROSS APPLY。基本语法为:

select [case],
  col+cast(seq as varchar(10)) seq,
  value
from
(
  SELECT [case], status, category,
    row_number() over(partition by [case] 
                      order by status) seq
  FROM yourTable
) d
cross apply
(
  select 'cat', category union all
  select 'status', status
) c (col, value)

请参阅SQL Fiddle with Demo这会将您的多列数据转换为如下所示:

| CASE |     SEQ | VALUE |
|------|---------|-------|
|    1 |    cat1 |    xx |
|    1 | status1 |    00 |
|    1 |    cat2 |   abc |
|    1 | status2 |    00 |
|    1 |    cat3 |   xyx |
|    1 | status3 |    01 |
|    2 |    cat1 |  asdf |
|    2 | status1 |    00 |

一旦数据采用这种格式,您就可以将PIVOT功能应用于它。

SELECT [case], cat1, status1, cat2, status2, cat3, status3
FROM
(
  select [case],
    col+cast(seq as varchar(10)) seq,
    value
  from
  (
    SELECT [case], status, category,
      row_number() over(partition by [case] 
                        order by status) seq
    FROM yourTable
  ) d
  cross apply
  (
    select 'cat', category union all
    select 'status', status
  ) c (col, value)
) x
PIVOT
(
   max(value)
   for seq in (cat1, status1, cat2, status2, cat3, status3)
)p;

请参阅SQL Fiddle with Demo

然后您可以将其转换为动态SQL:

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

select @cols = STUFF((SELECT  ',' + QUOTENAME(col+cast(seq as varchar(10))) 
                    from
                    (
                      select row_number() over(partition by [case] 
                                               order by category) seq
                      from yourtable
                    ) d
                    cross apply
                    (
                      select 'cat', 1 union all
                      select 'status', 2 
                    ) c (col, so)
                    group by seq, col, so
                    order by seq, so
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT [case],' + @cols + ' 
            from 
            (
              select [case],
                col+cast(seq as varchar(10)) seq,
                value
              from
              (
                SELECT [case], status, category,
                  row_number() over(partition by [case] 
                                    order by status) seq
                FROM yourTable
              ) d
              cross apply
              (
                select ''cat'', category union all
                select ''status'', status
              ) c (col, value)
            ) x
            pivot 
            (
                max(value)
                for seq in (' + @cols + ')
            ) p '

execute sp_executesql @query;

SQL Fiddle with Demo最终结果将是:

| CASE | CAT1 | STATUS1 |   CAT2 | STATUS2 |   CAT3 | STATUS3 |
|------|------|---------|--------|---------|--------|---------|
|    1 |   xx |      00 |    abc |      00 |    xyx |      01 |
|    2 | asdf |      00 |    ghj |      01 | (null) |  (null) |
|    3 | dfgh |      01 | (null) |  (null) | (null) |  (null) |