透视多个字段?

时间:2017-01-17 17:16:52

标签: sql sql-server sql-server-2012 pivot

我试图通过在第三列上旋转它们来聚合两列(希望这是正确的术语)。我让它以一种方式工作,但它看起来很笨重,所以我想知道是否有更好的方法。我发布了另外两种更易读但不起作用的方法。

演示数据:

DECLARE @counts TABLE (
    machineID INT,
    workShift INT,
    goodCount INT,
    totalCount INT
);

INSERT INTO @counts
VALUES
    (1, 1, 5, 20),
    (1, 1, 5, 20),
    (1, 2, 10, 20),
    (1, 2, 10, 20),
    (1, 2, 10, 20),
    (2, 1, 50, 200),
    (2, 1, 50, 200),
    (2, 2, 100, 200),
    (2, 2, 100, 200),
    (2, 2, 100, 200);

SELECT *
FROM @counts
ORDER BY machineID, workShift;

result:
machineID   workShift   goodCount   totalCount
1           1           5           20
1           1           5           20
1           2           10          20
1           2           10          20
1           2           10          20
2           1           50          200
2           1           50          200
2           2           100         200
2           2           100         200
2           2           100         200

#1 这很有效,但让我觉得我过于复杂了:

WITH goodTable AS (
    SELECT machineID, [1] AS g1, [2] AS g2
    FROM (SELECT machineID, goodCount, workShift FROM @counts) AS t
    PIVOT (SUM(goodCount) FOR workShift IN ([1], [2])) AS piv
    ),
totalTable AS (
    SELECT machineID, [1] AS t1, [2] AS t2
    FROM (SELECT machineID, totalCount, workShift FROM @counts) AS t
    PIVOT (SUM(totalCount) FOR workShift IN ([1], [2])) AS piv
    )
SELECT g.machineID, g1, t1, g2, t2
FROM goodTable as g
JOIN totalTable as t ON g.machineID = t.machineID
ORDER BY machineID;

result:
machineID   g1      t1      g2      t2
1           10      40      30      60
2           100     400     300     600

#2 我希望能够做到这样的事情,因为它非常易读,但不会编译。

SELECT 
    machineID,
    g.[1] AS g1,
    t.[1] AS t1,
    g.[2] AS g2,
    t.[2] AS t2
FROM @counts
PIVOT (SUM(goodCount) FOR workShift IN ([1], [2])) AS g
PIVOT (SUM(totalCount) FOR workShift IN ([1], [2])) AS t
ORDER BY machineID;

result:
The multi-part identifier "g.1" could not be bound.
The multi-part identifier "g.2" could not be bound.

#3 这是一种可行的解决方法,但却没有。它生成的额外行可以通过GROUP BY修复,但数字甚至不正确。我从这里得到了这个想法:https://social.msdn.microsoft.com/Forums/sqlserver/en-US/7db49578-a1ef-4e53-864b-c61c5e1150f7/how-do-i-aggregate-on-more-than-one-column-within-a-pivot?forum=transactsql

WITH countsPivotable AS (
    SELECT machineID, goodCount, totalCount,
    workshift AS ws1, 
    workshift + 10 AS ws2
    FROM @counts)
SELECT
    machineID, 
    [1] AS g1,
    [11] AS t1,
    [2] AS g2,
    [12] AS t2
FROM countsPivotable
PIVOT (SUM(goodCount) FOR ws1 IN ([1], [2])) AS piv
PIVOT (SUM(totalCount) FOR ws2 IN ([11], [12])) AS piv
ORDER BY machineID;

result:
machineID   g1      t1      g2      t2
1           NULL    NULL    30      20
1           10      20      NULL    NULL
2           NULL    NULL    300     200
2           100     200     NULL    NULL

我可以改变一些东西让#2或#3起作用吗?

有完全不同的方法更好吗?

奖励:如果要汇总的列多于我的简单示例,例如是否还有errorCounts列,该怎么办?或者如果有超过2个workShifts怎么办?我很好奇不同的解决方案是如何扩展的。

2 个答案:

答案 0 :(得分:2)

您可以跳过pivot()并使用旧样式数据透视表:

rextester:http://rextester.com/HXUE97581

select 
    MachineId
  , Good_1  = sum(case when workshift = 1 then goodcount else 0 end)
  , Total_1 = sum(case when workshift = 1 then totalcount else 0 end)
  , Good_2  = sum(case when workshift = 2 then goodcount else 0 end)
  , Total_2 = sum(case when workshift = 2 then totalcount else 0 end)
  from @counts
  group by MachineId

答案 1 :(得分:1)

这是动态版本。正如您所看到的,Cross Apply将取消您的数据

Declare @SQL varchar(max) = Stuff((Select Distinct ',' + QuoteName(concat('g',[workShift]))+',' + QuoteName(concat('t',[workShift])) From Yourtable  Order by 1 For XML Path('')),1,1,'') 
Select  @SQL = '
Select [machineID],' + @SQL + '
From (
        Select A.machineID
              ,B.*
         From  YourTable A
         Cross Apply (
                    Values (concat(''g'',A.workShift),A.goodCount)
                          ,(concat(''t'',A.workShift),A.totalCount)
               ) B (Item,Value)
     ) A
 Pivot (sum(Value) For [Item] in (' + @SQL + ') ) p'
Exec(@SQL);

返回

machineID   g1  t1  g2  t2
1           10  40  30  60
2           100 400 300 600

如果它对可视化有帮助,CROSS APPLY会生成以下内容:

enter image description here

Generated SQL看起来像这样:

Select [machineID],[g1],[t1],[g2],[t2]
From (
        Select A.machineID
              ,B.*
         From  YourTable A
         Cross Apply (
                    Values (concat('g',A.workShift),A.goodCount)
                          ,(concat('t',A.workShift),A.totalCount)
               ) B (Item,Value)
     ) A
 Pivot (sum(Value) For [Item] in ([g1],[t1],[g2],[t2]) ) p