SQLZoo HelpDesk问题:WHERE语句筛选前20%呼叫者的逻辑疑问
SQLZoo HelpDesk项目:80/20法则SQL语句WHERE子句逻辑解析
问题背景
我正在完成SQLZoo的HelpDesk项目,针对「验证80/20法则:统计最活跃20%呼叫者的呼叫占比」问题,找到了如下SQL解决方案,但无法理解最后一行WHERE语句的逻辑:
SELECT ROUND(SUM(b.calls_per_caller / (SELECT COUNT(*) FROM Issue) * 100), 4) as t20pc FROM ( SELECT a.*, @counter := @counter + 1 AS counter FROM (SELECT @counter := 0) AS initvar, (SELECT caller_id, COUNT(*) AS calls_per_caller FROM Issue GROUP BY caller_id ORDER BY COUNT(*) DESC) AS a ) AS b WHERE counter <= (20/100 * @counter)
我对@counter和counter的区别及其中的数学逻辑存在疑问:例如假设counter为30时,30<=6不成立;counter为10时,10<=2也不成立,但代码实际能得到正确结果。想请教该WHERE语句如何确保仅筛选出最活跃的20%呼叫者?
逻辑拆解
1. @counter与counter的本质区别
@counter是全局用户变量:
初始通过(SELECT @counter := 0) AS initvar赋值为0,之后在遍历排序后的呼叫者列表时,每处理一行就执行@counter := @counter + 1,等整个子查询b执行完毕,@counter的值等于系统中所有呼叫者的总数量。counter是行级序号字段:
它是每行的临时字段,值为当前行处理时@counter自增后的结果,代表该呼叫者的活跃度排名(呼叫量越高,排名越靠前,从1开始计数)。
2. WHERE子句的实际运行逻辑
你觉得矛盾是因为误解了@counter的取值时机:MySQL的查询执行顺序是先完成内层子查询b的所有计算,此时@counter已经固定为总呼叫者数,之后才会执行外层的WHERE筛选。
举个实际例子:
如果系统里总共有100个呼叫者,子查询b执行完后@counter的值是100,那么20/100 * @counter的结果就是20。此时WHERE条件变为counter <=20,直接筛选出排名前20的活跃呼叫者,统计他们的呼叫占比,完全符合80/20法则的验证需求。
你之前假设的counter=30时30<=6的情况不会出现——因为此时@counter是总呼叫者数(比如150),20%的计算结果是30,条件就变成30<=30,是成立的。
内容的提问来源于stack exchange,提问作者Anthony Garces
相关产品推荐
相关产品推荐

