1

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

该表有 5 列:

 - name
 - group
 - status
 - date
 - count

大约有 580 个不同的名称。

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

每个组都具有是或否的完整状态。

完成后,每个状态都会关联一个日期。否则,状态为 NULL。

计数列仅适用于 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

“名称”列将包含 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

4

1 回答 1

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 函数,那么您需要首先查看取消旋转status,datecount列,然后在最终结果中旋转它们。

UNPIVOT 是将多列数据转换为多行。您可以使用多种方法对statusdate和列进行反透视。count由于您使用的是 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)

请参阅演示。这给出了一个结果:

|  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

于 2013-08-23T22:01:41.077 回答