我试图通过在第三列上旋转它们来聚合两列(希望这是正确的术语)。我让它以一种方式工作,但它看起来很笨重,所以我想知道是否有更好的方法。我发布了另外两种更易读但不起作用的方法。
演示数据:
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怎么办?我很好奇不同的解决方案是如何扩展的。
答案 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
会生成以下内容:
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