SQL Double Dynamic Pivot

时间:2013-11-13 18:53:07

标签: sql sql-server-2008 pivot

我正在开发基于2列的双动态数据透视图(HardwarePhase& HardwarePhase_Result)。

使用下图中的第一个结果集,是我拥有的原始数据。每组5个项目(在图像中突出显示)基于HardwareTestCaseID进行分组。

图像中的第二个结果集是我从构建此查询的方式得到的当前结果。 理想情况,第二列的结果将是相同的结果,但它会将结果分组。

分组应该基于HardwareTestCaseID,但是,这种情况不会发生。

Current Results

此处显示了我实际想要的结果。 (应该有多行,但这只是每5个条目应该如何分组)。

Ideal Results

这是我目前使用的查询:

注意:@col变量是基于HardwarePhases(P0,M1,M2,M3)列表构建的。

select @query = 'SELECT ' + @colsNames + ',' +  @colsResultNames + ', HardwareTestCaseID FROM 
            (
                SELECT HardwarePhase_Result, HardwarePhase, ResultValue, HardwareTestCaseID, HardwareStatus
                FROM #temp4
            ) as x
            pivot 
            (
                 MAX(ResultValue)
                FOR HardwarePhase_Result IN (' + @colsResult + ')
            ) as p 
            pivot 
            (
                 MAX(HardwareStatus)
                FOR HardwarePhase IN (' + @cols + ')
            ) as p2 ';

使用此表:

create table #temp4
(
    HardwarePhase nvarchar(max),
    HardwarePhase_Result nvarchar(max),
    ResultValue bigint,
    HardwareTestCaseID bigint,
    HardwareStatus nvarchar(max),
    Block nvarchar(max)
);

2 个答案:

答案 0 :(得分:3)

我个人会稍微不同,因为你想在两列上进行PIVOT。我会先看看多列中的数据,然后应用PIVOT函数。我还建议您首先编写查询的硬编码版本,然后将其转换为动态SQL - 这样您就可以获得正确的逻辑。

要对数据进行取消操作,我会使用CROSS APPLY,这样您就可以同时将列对转换为行,语法类似于以下内容:

select col, value, HardwareTestCaseID
from temp4
cross apply
(
  select HardwarePhase, HardwareStatus union all
  select HardwarePhase_Result, cast(ResultValue as varchar(10))
) c (col, value)

SQL Fiddle with Demo。然后,您的数据格式为:

|       COL |       VALUE | HARDWARETESTCASEID |
|-----------|-------------|--------------------|
|        P0 | Not Started |                365 |
| P0_Result |           1 |                365 |
|        M1 |        Pass |                365 |
| M1_Result |           1 |                365 |
|        M4 |        Pass |                365 |
| M4_Result |           1 |                365 |
|        M2 |     Blocked |                365 |
| M2_Result |           1 |                365 |

然后您只需将数据透视功能应用于数据:

select M1, M2, M3, M4, P0,
  M1_Result, M2_Result, M3_Result,
  M4_Result, P0_Result,
  HardwareTestCaseID
from
(
  select col, value, HardwareTestCaseID
  from temp4
  cross apply
  (
    select HardwarePhase, HardwareStatus union all
    select HardwarePhase_Result, cast(ResultValue as varchar(10))
  ) c (col, value)
) d
pivot
(
  max(value)
  for col IN (M1, M2, M3, M4, P0,
              M1_Result, M2_Result, M3_Result,
              M4_Result, P0_Result)
) piv;

SQL Fiddle with Demo

关闭逻辑后,将其转换为动态SQL:

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

select @cols = STUFF((SELECT ',' + QUOTENAME(col) 
                    from temp4
                    cross apply
                    (
                      select HardwarePhase, 1 union all
                      select HardwarePhase_Result, 2
                    ) c (col, so)
                    group by col, so
                    order by so, col
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ' + @cols + ' , HardwareTestCaseID
            from 
            (
              select col, value, HardwareTestCaseID
              from temp4
              cross apply
              (
                select HardwarePhase, HardwareStatus union all
                select HardwarePhase_Result, cast(ResultValue as varchar(10))
              ) c (col, value)
            ) x
            pivot 
            (
                max(value)
                for col in (' + @cols + ')
            ) p '

execute sp_executesql @query;

SQL Fiddle with Demo。这个过程得到一个结果:

|      M1 |      M2 |      M3 |      M4 |          P0 | M1_RESULT | M2_RESULT | M3_RESULT | M4_RESULT | P0_RESULT | HARDWARETESTCASEID |
|---------|---------|---------|---------|-------------|-----------|-----------|-----------|-----------|-----------|--------------------|
|    Pass | Blocked |    Pass |    Pass | Not Started |         1 |         1 |         1 |         1 |         1 |                365 |
| Blocked | Blocked | Blocked | Blocked |        Pass |         1 |    (null) |         1 |         1 |         1 |                366 |

答案 1 :(得分:1)

--This is Just AWESOME. Simplified it for just one table as it's a much more common case (and could not find anything even close to this elegant after trying for hours)

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

select @cols = STUFF((SELECT ',' + QUOTENAME(your_key_column) 
                    from YOUR_ORIGINAL_KEY_AND_VALUE_TABLE
                    group by your_key_column
                    FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT your_row_heading_columns,' + @cols + '
            INTO YOUR_NEW_PIVOTED_TABLE
            from 
            (
              select your_row_heading_columns,your_key_column,your_value_column
              from YOUR_ORIGINAL_KEY_AND_VALUE_TABLE
            ) x
            pivot 
            (
                max(your_value_column)
                for your_key_column in (' + @cols + ')
            ) p '

execute sp_executesql @query;