【问题标题】:Maximum of COUNT by group and joining on EQUALS and NOT EQUALS condition按组最多 COUNT 并加入 EQUALS 和 NOT EQUALS 条件
【发布时间】:2017-03-30 16:18:50
【问题描述】:

我正在处理一个场景,我需要获取按 UserID 分组的计数,然后获取从分组的结果集中获得的最大计数。

然后,此最大计数将用于计算从分组结果集中获得的每一行的百分比。

这是一个例子:

这是我的样本数据:

 Users Table:   
  UserID        CountAsApproved  
    1                   1
    2                   1   
    1                   1
    2                   1
    3                   1
    3                   0
    4                   1
    1                   1
    4                   0

    Grouping Result:

  UserID            Counts
    1                 3
    2                 2
    3                 1
    4                 1

然后我需要获取最大计数(在这种情况下最大计数为 3) 然后计算百分比如下:

 UserID         Counts      MaxCount            Percentage
    1             3           3            (Count/MaxCount)*100
    2             2           3                 2/3 * 100
    3             1           3                 1/3 * 100
    4             1           3                 1/3 * 100

我目前有这样的查询:

    ;WITH Groups_CTE AS(
        SELECT UserID, COUNT(CountAsApproved) as Counts
        FROM Users 
        GROUP BY UserID),
MaxCount_CTE AS 
(
        SELECT MAX(Counts) AS MaxCount
        FROM Groups_CTE
)
SELECT 
        gc.UserID,
        gc.Counts,
        mc.MaxCount,
        CASE WHEN CAST(( ( gc.Counts
                                   / mc.MaxCount ) * 100 ) AS INT) = 0
                     THEN 1
                     ELSE CAST(( ( gc.Counts
                                   / mc.MaxCount ) * 100 ) AS INT)
                END AS Percentage
FROM    Groups_CTE gc CROSS JOIN MaxCount_CTE mc

当我对以下条件进行内部联接而不是交叉联接时,上述查询会产生相同的结果

FROM    Groups_CTE gc JOIN MaxCount_CTE mc
ON gc.Counts <> mc.MaxCount OR gc.Counts = mc.MaxCount

我只是想从性能角度或减少代码行数的角度检查是否有更好的方法来做到这一点。我得到相同的结果与任何一个连接,当我使用CROSS APPLY 时也没有条件。 我对使用两个 CTE 也有点犹豫。

让我知道您在即兴编写此代码时的想法和建议。

如果有帮助,我们执行这些操作的用户表可能包含数千行。

【问题讨论】:

  • 或 = 的意义何在?每一行都将满足该标准。它要么相等,要么不相等,除非它是 NULL,因为它是一个计数,所以它不能。您已经有效地创建了一个交叉连接。

标签: sql sql-server performance common-table-expression


【解决方案1】:

使用max() over():

select 
    userid
  , Counts     = sum(countasapproved)
  , MaxCount   = max(sum(countasapproved)) over()
  , Percentage = sum(countasapproved+.0)/max(sum(countasapproved)) over()
from Users 
group by userid

rextester 演示:http://rextester.com/TLG73597

返回:

+--------+--------+----------+------------+
| userid | Counts | MaxCount | Percentage |
+--------+--------+----------+------------+
|      1 |      3 |        3 | 1,000000   |
|      2 |      2 |        3 | 0,666666   |
|      3 |      1 |        3 | 0,333333   |
|      4 |      1 |        3 | 0,333333   |
+--------+--------+----------+------------+

【讨论】:

  • 我不太确定,但每次计算最大值和总和成本高吗?
  • @Kashyap 不,这不是它的工作原理。 over() 只对结果集进行操作,相同的表达式只计算一次。
【解决方案2】:

对聚合结果使用窗口函数:

select 
  userid, 
  sum(countasapproved) as counts, 
  max(sum(countasapproved)) over () as maxcount,
  sum(countasapproved) * 100.0 / max(sum(countasapproved)) over () as percentage
from users
group by userid;

【讨论】:

    【解决方案3】:

    根据数据量,子查询的性能可能会更高一些

    Select *
          ,MaxCount = max(Cnt) over ()
          ,PctCnt   = (Cnt+0.0) / max(Cnt) over ()
     From  (
            Select UserID
                  ,Cnt = sum(CountAsApproved)
             From YourTable 
             Group By UserID
           ) A
    

    返回

    UserID  Cnt MaxCount    PctCnt
    1       3   3           1.000000000000
    2       2   3           0.666666666666
    3       1   3           0.333333333333
    4       1   3           0.333333333333
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-09-11
      • 1970-01-01
      • 2014-10-09
      • 1970-01-01
      • 2012-02-20
      • 1970-01-01
      • 2012-10-17
      相关资源
      最近更新 更多