SUM OVER PARTITION BY

时间:2013-07-25 20:10:03

标签: sql sql-server tsql

我错过了什么?

此查询一遍又一遍地返回重复数据。计数对于一个完整的总计是正确的,但我期待一行,但我重复约40次。有什么想法吗?

SELECT BrandId
      ,SUM(ICount) OVER (PARTITION BY BrandId ) 
  FROM Table 
WHERE DateId  = 20130618

我明白了吗?

BrandId ICount
2       421762
2       421762
2       421762
2       421762
2       421762
2       421762
2       421762
1       133346
1       133346
1       133346
1       133346
1       133346
1       133346
1       133346

我错过了什么?

我无法删除分区,因为整个查询都是这样的:

SELECT BrandId
       ,SUM(ICount) OVER (PARTITION BY BrandId) 
       ,TotalICount= SUM(ICount) OVER ()    
        ,SUM(ICount) OVER () / SUM(ICount) OVER (PARTITION BY BrandId)  as Percentage
FROM Table 
WHERE DateId  = 20130618

返回此内容:

BrandId (No column name)    TotalICount Percentage
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76
2       421762              32239892    76

我希望输出类似于此而不必使用不同的:

BrandId (No column name)    TotalICount Percentage
2       421762              32239892    76
9       1238442             32239892    26
10      1467473             32239892    21

4 个答案:

答案 0 :(得分:30)

在我看来,我认为在使用OVER()子句和为什么进行求和时,解释为什么在你的SQL中需要一个GROUP BY是很重要的。当您期望每个BrandID占一行时,获取重复的数据行。

举个例子:您需要在两个日期之间汇总每个订单行的每个订单行的总销售价格,但您还需要在最终结果中保留单个订单数据。 SalesPrice列上的SUM()不允许您获取正确的总计,因为它需要GROUP BY,因此压缩细节因为您无法在select语句中保留各个订单行。

很多时候我们看到#temp表,@ table变量或CTE填充了我们的数据总和并进行了分组,以便我们稍后可以再次加入它以获得我们需要的总和列。这可以增加处理时间和额外的代码行。相反,使用OVER(PARTITION BY()),如下所示:

SELECT
  OrderLine, 
  OrderDateTime, 
  SalePrice, 
  OrderCategory,
  SUM(SalePrice) OVER(PARTITION BY OrderCategory) AS SaleTotalPerCategory
FROM tblSales 
WHERE OrderDateTime BETWEEN @StartDate AND @EndDate

注意我们没有分组,我们选择了单独的订单行列。最后一列中的PARTITION BY将返回每个类别中每行数据的总销售价格。最后一栏基本上是说,我们希望销售价格的总和 (SUM(SalePrice)) over 我的结果的分区 指定的类别 (OVER(PARTITION BY CategoryHere))

如果我们从select语句中删除其他列,并保留最后的SUM()列,如下所示:

SELECT
  SUM(SalePrice) OVER(PARTITION BY OrderCategory) AS SaleTotalPerCategory
FROM tblSales 
WHERE OrderDateTime BETWEEN @StartDate AND @EndDate

结果仍会对原始结果集中的每一行重复此总和。原因是这种方法不需要GROUP BY。如果您不需要保留单独的行数据,那么只需使用SUM()而不使用OVER()并对数据进行适当的分组。同样,如果您需要具有特定总计的其他列,则可以使用上述OVER(PARTITION BY())方法,而无需其他选择加入。

以上内容纯粹是为了解释为什么他会获得相同数字的重复行并帮助理解本条款提供的内容。这种方法可以在很多方面使用,我非常鼓励进一步阅读这里的文档:

Over Clause

答案 1 :(得分:10)

您可以使用DISTINCT或只删除PARTITION BY部分并使用GROUP BY

SELECT BrandId
       ,SUM(ICount)
       ,TotalICount = SUM(ICount) OVER ()    
       ,Percentage = SUM(ICount) OVER ()*1.0 / SUM(ICount) 
FROM Table 
WHERE DateId  = 20130618
GROUP BY BrandID

不确定为什么要将总计除以每个BrandID的计数,如果这是一个错误,你想要总数的百分比然后将这些位反转到:

SELECT BrandId
           ,SUM(ICount)
           ,TotalICount = SUM(ICount) OVER ()    
           ,Percentage = SUM(ICount)*1.0 / SUM(ICount) OVER () 
    FROM Table 
    WHERE DateId  = 20130618
    GROUP BY BrandID

答案 2 :(得分:7)

删除partition by并添加group by子句

SELECT BrandId
      ,SUM(ICount) totalSum
  FROM Table 
WHERE DateId  = 20130618
GROUP BY BrandId

答案 3 :(得分:7)

我认为您想要的查询是:

SELECT BrandId, SUM(ICount),
       SUM(sum(ICount)) over () as TotalCount,
       100.0 * SUM(ICount) / SUM(sum(Icount)) over () as Percentage
FROM Table 
WHERE DateId  = 20130618
group by BrandId;

这是品牌的group by。它计算“百分比”。此版本应生成0到100之间的数字。