带有可变行的SQL数据透视

时间:2016-01-25 16:55:24

标签: sql dynamic pivot

我必须在列中获得可变数量的行。我有类似的东西:

EMP                 EMP_ID  DIV_ID  ALLOCATION
Smith, Tom          3605    11300   20.00
Smith, Tom          13605   11310   80.00
Benetar, Pat        7460    11012   25.00
Benetar, Pat        7460    11015   75.00
Walkin, Chris       13892   11012   90.00
Walkin, Chris       13892   11015   10.00
Kent, Clark         12262   10015   50.00
Kent, Clark         12262   11210   25.00
Kent, Clark         12262   11220   25.00

我正在寻找的是:

EMP           EMP_ID        DIV_ID_01     DIV_01_ALOC    DIV_ID_02     DIV_02_ALOC    DIV_ID_03     DIV_03_ALOC
Smith, Tom    3605          11300         20.00          11310         80.00
Benetar, Pat  13605         11012         25.00          11015         75.00
Walkin, Chris 13892         11012         90.00          11015         10.00
Kent, Clark   12262         11015         50.00          11210         25.00          11220         25.00

我想避免使用大量的CASE语句。我现在正在尝试使用枢轴,但是在标题上遇到了困难。

2 个答案:

答案 0 :(得分:0)

更新:

经过几次尝试后,我想出了下面的解决方案,该解决方案使用了两个GROUP BY函数和一个with testdata(Emp, EMP_ID, DIV_ID, ALLOCATION) as ( select 'Smith, Tom',3605, 11300,20.00 union all select 'Smith, Tom',3605, 11310, 80.00 union all select 'Benetar, Pat',7460, 11012,25.00 union all select 'Benetar, Pat',7460, 11015,75.00 union all select 'Walkin, Chris',13892, 11012, 90.00 union all select 'Walkin, Chris', 13892, 11015, 10.00 union all select 'Kent, Clark', 12262, 10015, 50.00 union all select 'Kent, Clark', 12262, 11210, 25.00 union all select 'Kent, Clark', 12262, 11220, 25.00 ) SELECT Emp ,EMP_ID ,MAX([Div1]) AS DIV_ID_01 ,MAX([Alloc1]) AS DIV_01_ALOC ,MAX([Div2]) AS DIV_ID_02 ,MAX([Alloc2]) AS DIV_02_ALOC ,MAX([Div3]) AS DIV_ID_03 ,MAX([Alloc3]) AS DIV_03_ALOC FROM ( SELECT * ,cast(dense_rank() OVER (PARTITION BY emp_id ORDER BY div_id asc) AS nvarchar) AS [emp_rnk] ,'Alloc' + cast(dense_rank() OVER (PARTITION BY emp_id ORDER BY div_id asc) AS nvarchar) AS [piv_Alloc_rnk] ,'Div' + cast(dense_rank() OVER (PARTITION BY emp_id ORDER BY div_id asc) AS nvarchar) AS [piv_Div_rnk] FROM testdata td ) query /* After both PIVOT functions are compplete, it still returns a single row for each EMP_ID. So further aggregation is needed to 'flatten' the result. */ PIVOT (Max(Div_id) FOR [piv_Div_rnk] IN ([Div1],[Div2],[Div3])) AS pivot1 PIVOT (Max(Allocation) FOR [piv_Alloc_rnk] in([Alloc1],[Alloc2],[Alloc3])) AS pivot2 /* Since there is only one value in each of the columns created by the PIVOTS for each EMP_ID taking the MAX() value and grouping by EMP and EMP_ID flattens the result down to the desired output. */ GROUP BY emp, emp_id ORDER BY DIV_ID_01 DESC 来匹配您的预期结果。

以下是代码。注意:这适用于SQL Server 2005 +

EXTRA x509.UnknownAuthorityError=x509: certificate signed by unknown authority

答案 1 :(得分:0)

仅供参考,如果你试图在这里使用动态PIVOT,你最终需要一个看起来像这样的查询。

SELECT  [EMP],
        [EMP_ID],
        MIN(DIV_ID_1) [DIV_ID_1],
        SUM(DIV_1_ALOC) [DIV_1_ALOC],
        MIN(DIV_ID_2) [DIV_ID_2],
        SUM(DIV_2_ALOC) [DIV_2_ALOC],
        MIN(DIV_ID_3) [DIV_ID_3],
        SUM(DIV_3_ALOC) [DIV_3_ALOC]
FROM    (SELECT [EMP],
                [EMP_ID],
                [DIV_ID],
                [ALLOCATION],
                CONCAT('DIV_ID_',DENSE_RANK () OVER (PARTITION BY [EMP] ORDER BY [DIV_ID])) ID_RN,
                CONCAT('DIV_',DENSE_RANK () OVER (PARTITION BY [EMP] ORDER BY [DIV_ID]),'_ALOC') ALLOC_RN
         FROM   EmpTable
        ) t 
PIVOT   ( 
        MIN([DIV_ID]) 
        FOR ID_RN IN ([DIV_ID_1],[DIV_ID_2],[DIV_ID_3]) ) p1 
PIVOT   ( 
        SUM([ALLOCATION]) 
        FOR ALLOC_RN IN ([DIV_1_ALOC],[DIV_2_ALOC],[DIV_3_ALOC]) ) p2
GROUP BY [EMP],
        [EMP_ID]

由于双轴,你需要动态创建SELECT和PIVOT列。

另一方面,如果你使用CASE语句,你只需要动态创建SELECT,因为那个查询看起来像

SELECT  [EMP],
        [EMP_ID],
        MIN(CASE WHEN RN = 1 THEN [DIV_ID] END) [DIV_ID_1],
        SUM(CASE WHEN RN = 1 THEN [ALLOCATION] END) [DIV_1_ALOC],
        MIN(CASE WHEN RN = 2 THEN [DIV_ID] END) [DIV_ID_2],
        SUM(CASE WHEN RN = 2 THEN [ALLOCATION] END) [DIV_2_ALOC],
        MIN(CASE WHEN RN = 3 THEN [DIV_ID] END) [DIV_ID_3],
        SUM(CASE WHEN RN = 3 THEN [ALLOCATION] END) [DIV_3_ALOC]
FROM    (
            SELECT  *,
                    DENSE_RANK () OVER (PARTITION BY [EMP] ORDER BY [DIV_ID]) RN 
            FROM    EmpTable
        ) t
GROUP BY [EMP],
        [EMP_ID]

您的动态陈述看起来像

DECLARE @CaseSelect VARCHAR(MAX)
SELECT  @CaseSelect = COALESCE(@CaseSelect + ',','') 
                + 'MIN(CASE WHEN RN = ' + RN + ' THEN [DIV_ID] END) [DIV_ID_' + RN + '],'
                + 'SUM(CASE WHEN RN = ' + RN + ' THEN [ALLOCATION] END) [DIV_' + RN + '_ALOC]'
FROM    (
    SELECT DISTINCT CONVERT(VARCHAR(2),DENSE_RANK () OVER (PARTITION BY [EMP] ORDER BY [DIV_ID])) RN 
    FROM EmpTable 
) t 
ORDER BY RN

DECLARE @SQL VARCHAR(MAX)
SET     @SQL = '
    SELECT  [EMP],
            [EMP_ID], '
            + @CaseSelect + '
    FROM    (
        SELECT  *,
                DENSE_RANK () OVER (PARTITION BY [EMP] ORDER BY [DIV_ID]) RN 
        FROM    EmpTable
    ) t
    GROUP BY [EMP], [EMP_ID]
'

EXEC(@SQL)

用您实际的表名称替换EmpTable