SQL Server Management Studio 2012数据透视/交叉选项卡查询

时间:2013-08-23 21:51:11

标签: sql-server

我正在使用SQL Server Management Studio 2012,并希望为超过2300行的表创建数据透视/交叉制表符查询。

该表有5列:

 - name
 - group
 - status
 - date
 - count

大约有580个不同的名字。

每个名称与4个不同的组(A,B,C和D)相关联。

每个小组的完整状态为是或否。

完成后,日期与每个状态相关联。否则,状态为NULL。

count列仅适用于B组和D组,是一个整数值。

样品A:

name    group  status   date    count
A.A.1     A     yes     5/23    NULL
A.A.1     B     yes     5/27    112
A.A.1     C     yes     6/4     NULL
A.A.1     D     yes     6/15    122
A.B.2     A     yes     5/25    NULL
A.B.2     B     yes     6/1     119
A.B.2     C     no      NULL    NULL
A.B.2     D     no      NULL    NULL

我正在尝试将每个名称的状态显示为11列中的字段值:

 - name
 - group A
 - group A date
 - group B
 - group B date
 - group B count
 - group C
 - group C date
 - group D
 - group D date
 - group D count

'name'列将包含580个不同的名称及其对应的A,B,C和D组数据。

样本B:

nm      grp_A   A_day   grp_B   B_day   B_ct    grp_C   C_day   grp_D   D_day   D_ct
A.A.1   yes     5/23    yes     5/27    112     yes     6/4     yes     6/15    122
A.B.2   yes     5/25    yes     6/1     119     no      NULL    no      NULL    NULL

列名已更改为符合此问题部分的格式

最终,结果应该在第一列中包含所有580个不同的名称,并且每个组的对应状态,完成日期(如果尚未完成则为NULL),以及组B和D的计数。

我尝试过使用CASE语句,但它为每个组生成一次名称,导致原始表格在11个库存中间隔开。

样本C:

nm     grp_A    A_day   grp_B   B_day   B_ct    grp_C   C_day   grp_D   D_day   D_ct
A.A.1   yes     5/23                                
A.A.1                    yes    5/27    112         
A.A.1                                             yes   6/4         
A.A.1                                                            yes    6/15    122
A.B.2   yes     5/25                                
A.B.2                    yes    6/1     119         
A.B.2                                             no    NULL            
A.B.2                                                             no    NULL    NULL

我做错了什么?请帮忙!

- K-moj

1 个答案:

答案 0 :(得分:1)

我没有看到您的查询,但是如果您尝试使用CASE表达式对数据进行PIVOT,我的建议是在CASE周围添加聚合函数。

select
  name,
  max(case when [group] = 'A' then status end) grp_A,
  max(case when [group] = 'A' then date end) A_day,
  max(case when [group] = 'A' then [count] end) A_ct,
  max(case when [group] = 'B' then status end) grp_B,
  max(case when [group] = 'B' then date end) B_day,
  max(case when [group] = 'B' then [count] end) B_ct,
  max(case when [group] = 'C' then status end) grp_C,
  max(case when [group] = 'C' then date end) C_day,
  max(case when [group] = 'C' then [count] end) C_ct,
  max(case when [group] = 'D' then status end) grp_D,
  max(case when [group] = 'D' then date end) D_day,
  max(case when [group] = 'D' then [count] end) D_ct
from yourtable
group by name

请参阅SQL Fiddle with Demo

如果你想使用PIVOT功能,你需要首先看看statusdatecount列的隐蔽,然后在最终结果中转动它们。

UNPIVOT是将多列数据转换为多行的时候。您可以使用各种方法取消忽略statusdatecount列。由于您使用的是SQL Server 2012,因此可以将CROSS APPLY与VALUES子句一起使用。将列转换为行的代码为:

select name, 
  col = col+'_'+[group], 
  value
from yourtable 
cross apply
(
  values 
    ('grp', status),
    ('day', [date]),
    ('ct', cast([count] as varchar(10)))
) c(col, value)

Demo。这给出了一个结果:

|  NAME |   COL |  VALUE |
| A.A.1 | grp_A |    yes |
| A.A.1 | day_A |   5/23 |
| A.A.1 |  ct_A | (null) |
| A.A.1 | grp_B |    yes |
| A.A.1 | day_B |   5/27 |
| A.A.1 |  ct_B |    112 |

现在,您可以将所有值转换为value中的新列和col中的新列名,而不是要使用多个要转动的列。然后,您可以应用PIVOT函数,因此完整代码将类似于以下内容:

select name,
  grp_A, day_A, ct_A,
  grp_B, day_B, ct_B,
  grp_C, day_C, ct_C,
  grp_D, day_D, ct_D
from
(
  select name, 
    col = col+'_'+[group], 
    value
  from yourtable 
  cross apply
  (
    values 
      ('grp', status),
      ('day', [date]),
      ('ct', cast([count] as varchar(10)))
  ) c(col, value)
) d
pivot
(
  max(value)
  for col in (grp_A, day_A, ct_A,
              grp_B, day_B, ct_B,
              grp_C, day_C, ct_C,
              grp_D, day_D, ct_D)
) piv

请参阅SQL Fiddle with Demo