使用 PIVOT 时未在 SQL Server 2012 中获得正确的 SUM 值
Not getting the correct SUM values in SQL Server 2012 when using a PIVOT
我正在尝试创建一个查询,该查询将以某些行为中心,但将 SUM
某些列,然后将它们组合在一起。我之前使用过 PIVOT
函数,但当我的结果集包含相似值时,我 运行 遇到了问题。
这是 SQL Server 2012。
示例代码:
CREATE TABLE #Foo
(
Store varchar(50),
Employee varchar(50),
Sold money,
Waste money,
Tmsp datetime
)
INSERT INTO #Foo
VALUES
('Harrisburg', 'John', 20.00, 10.00, GETDATE()),
('Harrisburg', 'John', 20.00, 10.00, GETDATE()),
('Harrisburg', 'Jim', 20.00, 10.00, GETDATE()),
('Seattle', 'Jim', 20.00, 10.00, GETDATE()),
('Seattle', 'Alex', 20.00, 10.00, GETDATE())
SELECT
Store,
SUM(Sold) TotalSold,
SUM([John]) WastedByJohn,
SUM([Jim]) WastedByJim,
SUM([Alex]) WastedByAlex
FROM
#Foo
PIVOT
(SUM(Waste)
FOR Employee IN ([John], [Jim], [Alex])
) PVT
GROUP BY
Store
DROP TABLE #Foo
这会产生以下结果:
Store | TotalSold | WastedByJohn | WastedByJim | WastedByAlex
Harrisburg | 20.00 | 20.00 | 10.00 | NULL
Seattle | 20.00 | NULL | 10.00 | 10.00
根据 table 中的数据,Harrisburg 的 TotalSold 和 Seattle 的 TotalSold 不应该是 60.00 吗?
我越来越难以理解,因为如果我更改数据使值不相同,我会得到正确的结果。
INSERT INTO #Foo
VALUES
('Harrisburg', 'John', 25.00, 10.00, GETDATE()),
('Harrisburg', 'John', 30.00, 10.00, GETDATE()),
('Harrisburg', 'Jim', 40.00, 10.00, GETDATE()),
('Seattle', 'Jim', 50.00, 10.00, GETDATE()),
('Seattle', 'Alex', 60.00, 10.00, GETDATE())
这组数据产生了预期的结果:
Store | TotalSold | WastedByJohn | WastedByJim | WastedByAlex
Harrisburg | 95.00 | 20.00 | 10.00 | NULL
Seattle | 110.00 | NULL | 10.00 | 10.00
我环顾四周,找不到关于为什么 PIVOT 在聚合时会基于不同值而不同的答案。我觉得我在这里缺少一些基本的东西,除非我碰巧遇到 SQL 服务器的一些问题,这不太可能。
如有任何帮助,我们将不胜感激。
谢谢!
以下查询应该可以满足您的需求:
SELECT Store,
TotalSold,
[John] AS WastedByJohn,
[Jim] AS WastedByJim,
[Alex] AS WastedByAlex
FROM (SELECT Store, Employee, Waste,
SUM(Sold) OVER (PARTITION BY Store) AS TotalSold
FROM #Foo) src
PIVOT
(SUM(Waste)
FOR Employee IN ([John], [Jim], [Alex])
) PVT
要了解为什么会出现意外结果,请尝试不使用 GROUP BY
子句的查询:
SELECT Store, Sold, [John], [Jim], [Alex]
FROM
#Foo
PIVOT
(SUM(Waste)
FOR Employee IN ([John], [Jim], [Alex])
) PVT
输出:
Store Sold John Jim Alex
Harrisburg 20,00 20,00 10,00 NULL
Seattle 20,00 NULL 10,00 10,00
现在,用第二个版本的示例数据再次尝试相同的操作:
输出:
Store Sold John Jim Alex
Harrisburg 25,00 10,00 NULL NULL
Harrisburg 30,00 10,00 NULL NULL
Harrisburg 40,00 NULL 10,00 NULL
Seattle 50,00 NULL 10,00 NULL
Seattle 60,00 NULL NULL 10,00
通过比较 2 个不同的结果集,您可以清楚地看到 PIVOT
发生在未参与其中的每个列组合,即 Store
、Sold
的每个组合.
在第一种情况下只有 Harrisburg,20,00
和 Seattle,20,00
。这就是为什么在这种情况下你只能得到两行。在第二种情况下,您总共有 3 + 2 = 5 种组合。
您现在可以明白为什么 GROUP BY
只适用于第二种情况了。
您没有了解数据透视表的含义。让我解释。首先有3个要素:传播、聚合和分组。
传播是你在列中得到的,即 Employee IN ([John], [Jim], [Alex])
。聚合为 SUM(Waste)
。那么什么是分组元素呢?最后一个是通过消除列来确定的。 IE。每列,但聚合和传播。在您的示例中,它将是 Store, Sold, Tps
。它将按这 3 列对数据进行分组。但你不想要这个。您只想按 Store
分组。那么该怎么办?我可以建议使用条件聚合:
SELECT
Store,
SUM(Sold) TotalSold,
SUM(CASE WHEN Employee = 'John' THEN Waste ELSE 0 END) WastedByJohn,
SUM(CASE WHEN Employee = 'Jim' THEN Waste ELSE 0 END) WastedByJim,
SUM(CASE WHEN Employee = 'Alex' THEN Waste ELSE 0 END) WastedByAlex
FROM #Foo
GROUP BY Store
我正在尝试创建一个查询,该查询将以某些行为中心,但将 SUM
某些列,然后将它们组合在一起。我之前使用过 PIVOT
函数,但当我的结果集包含相似值时,我 运行 遇到了问题。
这是 SQL Server 2012。
示例代码:
CREATE TABLE #Foo
(
Store varchar(50),
Employee varchar(50),
Sold money,
Waste money,
Tmsp datetime
)
INSERT INTO #Foo
VALUES
('Harrisburg', 'John', 20.00, 10.00, GETDATE()),
('Harrisburg', 'John', 20.00, 10.00, GETDATE()),
('Harrisburg', 'Jim', 20.00, 10.00, GETDATE()),
('Seattle', 'Jim', 20.00, 10.00, GETDATE()),
('Seattle', 'Alex', 20.00, 10.00, GETDATE())
SELECT
Store,
SUM(Sold) TotalSold,
SUM([John]) WastedByJohn,
SUM([Jim]) WastedByJim,
SUM([Alex]) WastedByAlex
FROM
#Foo
PIVOT
(SUM(Waste)
FOR Employee IN ([John], [Jim], [Alex])
) PVT
GROUP BY
Store
DROP TABLE #Foo
这会产生以下结果:
Store | TotalSold | WastedByJohn | WastedByJim | WastedByAlex
Harrisburg | 20.00 | 20.00 | 10.00 | NULL
Seattle | 20.00 | NULL | 10.00 | 10.00
根据 table 中的数据,Harrisburg 的 TotalSold 和 Seattle 的 TotalSold 不应该是 60.00 吗?
我越来越难以理解,因为如果我更改数据使值不相同,我会得到正确的结果。
INSERT INTO #Foo
VALUES
('Harrisburg', 'John', 25.00, 10.00, GETDATE()),
('Harrisburg', 'John', 30.00, 10.00, GETDATE()),
('Harrisburg', 'Jim', 40.00, 10.00, GETDATE()),
('Seattle', 'Jim', 50.00, 10.00, GETDATE()),
('Seattle', 'Alex', 60.00, 10.00, GETDATE())
这组数据产生了预期的结果:
Store | TotalSold | WastedByJohn | WastedByJim | WastedByAlex
Harrisburg | 95.00 | 20.00 | 10.00 | NULL
Seattle | 110.00 | NULL | 10.00 | 10.00
我环顾四周,找不到关于为什么 PIVOT 在聚合时会基于不同值而不同的答案。我觉得我在这里缺少一些基本的东西,除非我碰巧遇到 SQL 服务器的一些问题,这不太可能。
如有任何帮助,我们将不胜感激。
谢谢!
以下查询应该可以满足您的需求:
SELECT Store,
TotalSold,
[John] AS WastedByJohn,
[Jim] AS WastedByJim,
[Alex] AS WastedByAlex
FROM (SELECT Store, Employee, Waste,
SUM(Sold) OVER (PARTITION BY Store) AS TotalSold
FROM #Foo) src
PIVOT
(SUM(Waste)
FOR Employee IN ([John], [Jim], [Alex])
) PVT
要了解为什么会出现意外结果,请尝试不使用 GROUP BY
子句的查询:
SELECT Store, Sold, [John], [Jim], [Alex]
FROM
#Foo
PIVOT
(SUM(Waste)
FOR Employee IN ([John], [Jim], [Alex])
) PVT
输出:
Store Sold John Jim Alex
Harrisburg 20,00 20,00 10,00 NULL
Seattle 20,00 NULL 10,00 10,00
现在,用第二个版本的示例数据再次尝试相同的操作:
输出:
Store Sold John Jim Alex
Harrisburg 25,00 10,00 NULL NULL
Harrisburg 30,00 10,00 NULL NULL
Harrisburg 40,00 NULL 10,00 NULL
Seattle 50,00 NULL 10,00 NULL
Seattle 60,00 NULL NULL 10,00
通过比较 2 个不同的结果集,您可以清楚地看到 PIVOT
发生在未参与其中的每个列组合,即 Store
、Sold
的每个组合.
在第一种情况下只有 Harrisburg,20,00
和 Seattle,20,00
。这就是为什么在这种情况下你只能得到两行。在第二种情况下,您总共有 3 + 2 = 5 种组合。
您现在可以明白为什么 GROUP BY
只适用于第二种情况了。
您没有了解数据透视表的含义。让我解释。首先有3个要素:传播、聚合和分组。
传播是你在列中得到的,即 Employee IN ([John], [Jim], [Alex])
。聚合为 SUM(Waste)
。那么什么是分组元素呢?最后一个是通过消除列来确定的。 IE。每列,但聚合和传播。在您的示例中,它将是 Store, Sold, Tps
。它将按这 3 列对数据进行分组。但你不想要这个。您只想按 Store
分组。那么该怎么办?我可以建议使用条件聚合:
SELECT
Store,
SUM(Sold) TotalSold,
SUM(CASE WHEN Employee = 'John' THEN Waste ELSE 0 END) WastedByJohn,
SUM(CASE WHEN Employee = 'Jim' THEN Waste ELSE 0 END) WastedByJim,
SUM(CASE WHEN Employee = 'Alex' THEN Waste ELSE 0 END) WastedByAlex
FROM #Foo
GROUP BY Store