28

我错过了什么?

此查询一遍又一遍地返回重复数据。计数对于一个完整的总数是正确的,但我期待一行,但我得到的值重复了大约 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

4 回答 4

47

在我看来,我认为重要的是解释为什么在使用 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 将为我们返回每个类别中每行数据的销售价格总额。最后一列本质上说的是,我们想要我的结果分区和指定类别( OVER(PARTITION BY CategoryHere))销售价格总和(SUM(SalePrice) ) 。

如果我们从 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 ()) 方法,而无需额外的选择来加入。

上述内容纯粹是为了解释为什么他会得到相同数字的重复行,并帮助理解该子句提供的内容。此方法可以以多种方式使用,我强烈建议您进一步阅读此处的文档:

过条款

于 2014-12-20T21:43:53.560 回答
19

您可以使用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
于 2013-07-25T20:21:37.593 回答
14

我认为你想要的查询是这样的:

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 之间的数字。

于 2013-07-25T20:21:34.030 回答
9

删除partition by和添加group by子句,

SELECT BrandId
      ,SUM(ICount) totalSum
  FROM Table 
WHERE DateId  = 20130618
GROUP BY BrandId
于 2013-07-25T20:11:10.950 回答