SQL Server中如何基于另一列累计和阈值筛选指定列取值
报错原因
你写的SQL触发8120错误的核心原因是:子查询中同时使用了普通聚合函数SUM(CALLS_DROPS)和非聚合字段DEVICE_TYPE,但没有添加GROUP BY DEVICE_TYPE子句,SQL语法不允许未分组的普通聚合函数与非聚合字段混用。
另外你原有逻辑也和需求不匹配:
- 窗口函数用了
PARTITION BY DEVICE_TYPE,计算的是单个品牌的总消费,不是按降序排序后的累计消费和 - 阈值系数错写为0.85,需求要求的是全量总分钟数的70%,对应系数0.7
正确实现方案
实现逻辑
- 先按设备品牌聚合,得到每个品牌的总消费分钟数,同时计算全量总消费的70%作为阈值
- 对聚合后的品牌按总消费分钟数降序排序,计算累加消费和
- 筛选出累加和小于等于阈值的所有品牌,再加上第一个让累加和超过阈值的品牌,刚好覆盖到70%的占比要求
可运行SQL(支持MySQL8.0+、SQL Server、PostgreSQL等所有支持窗口函数的数据库)
WITH brand_total AS ( -- 按品牌汇总总消费,同时计算全量70%阈值 SELECT 设备品牌 AS device_type, SUM(总消费分钟数) AS total_minutes, SUM(SUM(总消费分钟数)) OVER() * 0.7 AS cutoff FROM 你的业务表名 -- 替换成你实际的表名即可 GROUP BY 设备品牌 ), running_calculate AS ( -- 按总消费降序排序,计算累计消费 SELECT device_type, total_minutes, cutoff, SUM(total_minutes) OVER(ORDER BY total_minutes DESC) AS accumulate_total FROM brand_total ) -- 筛选符合要求的头部品牌 SELECT device_type FROM running_calculate WHERE accumulate_total <= cutoff OR (accumulate_total > cutoff AND accumulate_total - total_minutes <= cutoff)
拿你给出的示例数据验证:全量总消费72,70%阈值为50.4,聚合后苹果总消费32、三星22、华为17,累加后苹果32≤50.4,三星累加后为54>50.4且减去自身后的32≤50.4,所以最终返回Apple、Samsung两个品牌,完全符合需求。
内容的提问来源于stack exchange,提问作者SIDDHARTHA MAHENDRA
相关产品推荐
相关产品推荐

