【问题标题】:Not getting the correct SUM values in SQL Server 2012 when using a PIVOT使用 PIVOT 时未在 SQL Server 2012 中获取正确的 SUM 值
【发布时间】:2015-08-31 11:51:13
【问题描述】:

我正在尝试创建一个查询,该查询将以某些行为中心,但会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

根据表中的数据,Harrisburg 的 TotalSold 是否应该是 60.00 而西雅图的 TotalSold 应该是 40.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 Server 问题。

任何帮助将不胜感激。

谢谢!

【问题讨论】:

  • 您如何在预期输出中获得 95 和 110 的总值?应该是 40 和 60 ,,, 不应该吗????
  • 我希望它是“Sold”的 SUM 值,按商店分组。在第一个示例中,我预计哈里斯堡为 20+20+20 = 60,西雅图为 20+20=40。由于所有行的“Sold”值相同 (20.00),某些东西似乎无法正常工作。对于第二个数据集,“Sold”的值不同,并且总和工作正常(哈里斯堡为 25+30+40=95,西雅图为 50+60=110)

标签: sql-server sql-server-2012 pivot distinct aggregate-functions


【解决方案1】:

下面的查询应该会给你你想要的:

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 仅在第二种情况下有效。

【讨论】:

  • 非常感谢! “PIVOT 发生在不参与其中的每个列组合,即对于 Store, Sold 的每个组合”是我所缺少的!
【解决方案2】:

您没有得到 pivot 语句的作用。让我解释。首先有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

【讨论】:

    猜你喜欢
    • 2014-03-20
    • 1970-01-01
    • 1970-01-01
    • 2016-09-03
    • 1970-01-01
    • 2013-03-24
    • 2016-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多