Sql 透视多个字段?
我试图通过将两列分别放在第三列上来聚合它们(希望这是正确的术语)。我让它以一种方式工作,但它似乎笨重,所以我想知道是否有更好的方式。我发布了另外两种更具可读性但不起作用的方法 演示数据:Sql 透视多个字段?,sql,sql-server,sql-server-2012,pivot,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
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
修复,但数字甚至不正确。我从这里得到了这个想法:
我能换些东西让2号或3号开始工作吗
有完全不同的方法更好吗
额外好处:如果要聚合的列比我的简单示例中的多,比如如果还有一个errorCounts列,该怎么办?或者,如果有两个以上的工作班次怎么办?我很好奇不同的解决方案是如何扩展的。您可以跳过
pivot()
,像这样使用老式的pivot:
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
雷克斯测试仪:
您可以跳过
pivot()
,像这样使用旧式pivot:
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 @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
如果有助于可视化,则交叉应用将生成以下内容:
生成的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 @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
如果有助于可视化,则交叉应用将生成以下内容:
生成的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
在重新阅读您的问题后,不清楚您想要的输出。。。聚合总计数还是不同的总计数?我在寻找每班期间每台机器的
goodCount
之和,以及每班期间每台机器的totalCount
之和。我的解决方案底部的结果#1显示了我正在寻找的结果。在重新阅读您的问题后,返回到我的原始答案,不清楚您想要的输出。。。聚合总计数还是不同的总计数?我在寻找每班期间每台机器的goodCount
之和,以及每班期间每台机器的totalCount
之和。我的解决方案底部的结果#1显示了我正在寻找的结果。返回到我的原始答案当我用@counts
替换
时,生成的SQL运行良好。但是,当我对动态SQL执行同样的操作时,我得到一个错误必须声明表变量@counts
。发生了什么?@MarredCheese否。表变量在动态SQL中不可见,除非它们在动态SQL中定义。你可以使用临时表,它们是可见的。啊,好的。谢谢你的帮助!这是一个艰难的决定,但我选择SqlZim的答案仅仅是因为它是我实际要使用的(由于它的简单性)。然而,我真的很欣赏你的答案的可伸缩性,所以我对它投了更高的票。@MarredCheese条件聚合始终是我的第一选择。也就是说,我更喜欢动态的Pivot。(更易于动态构造)当我将YourTable
替换为@counts
时,生成的SQL非常有效。但是,当我对动态SQL执行同样的操作时,我得到一个错误必须声明表变量@counts
。发生了什么?@MarredCheese否。表变量在动态SQL中不可见,除非它们在动态SQL中定义。你可以使用临时表,它们是可见的。啊,好的。谢谢你的帮助!这是一个艰难的决定,但我选择SqlZim的答案仅仅是因为它是我实际要使用的(由于它的简单性)。然而,我真的很欣赏你的答案的可伸缩性,所以我对它投了更高的票。@MarredCheese条件聚合始终是我的第一选择。也就是说,我更喜欢动态的Pivot。(更易于动态构造)