旋转多个字段?
Pivot multiple fields?
我试图通过在第三列上旋转每列来聚合两列(希望这是正确的术语)。我让它以一种方式工作,但它看起来很笨重,所以我想知道是否有更好的方法。我发布了另外两种更具可读性但不起作用的方法。
演示数据:
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 怎么办?我很好奇不同的解决方案如何扩展。
您可以跳过 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
这是一个动态版本。如您所见,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);
Returns
machineID g1 t1 g2 t2
1 10 40 30 60
2 100 400 300 600
如果它有助于可视化,CROSS APPLY
会生成以下内容:
生成的 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
我试图通过在第三列上旋转每列来聚合两列(希望这是正确的术语)。我让它以一种方式工作,但它看起来很笨重,所以我想知道是否有更好的方法。我发布了另外两种更具可读性但不起作用的方法。
演示数据:
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 怎么办?我很好奇不同的解决方案如何扩展。
您可以跳过 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
这是一个动态版本。如您所见,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);
Returns
machineID g1 t1 g2 t2
1 10 40 30 60
2 100 400 300 600
如果它有助于可视化,CROSS APPLY
会生成以下内容:
生成的 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