涉及Date、Child、Sweets eaten字段的SQL查询问题求助
解题思路
题目核心需求为:基于记录孩子每日吃糖数量的表(包含Date日期、Child孩子姓名、Sweets eaten当日吃糖数三个字段),查询每个日期节点上,从统计起始日到当日累计吃糖总数最高的孩子,若存在多个孩子并列累计最高,需全部返回。
实现分三步:
- 第一步:按孩子维度分组,按日期升序累加,计算每个孩子在每个日期对应的历史累计吃糖总数
- 第二步:按日期维度分组,对当日所有孩子的累计吃糖数做降序排名,累计值相同的记录保留相同名次
- 第三步:过滤出所有排名为1的记录,即为对应日期累计吃糖最高的结果
参考代码
支持窗口函数的数据库写法(兼容MySQL 8.0+、PostgreSQL、SQL Server等主流数据库)
用窗口函数写法逻辑清晰,执行效率更高:
-- 注意替换下方sweets_table为你实际使用的表名 WITH cumulative_stat AS ( SELECT Date, Child, SUM(`Sweets eaten`) OVER ( PARTITION BY Child ORDER BY Date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW ) AS total_sweets FROM sweets_table ), rank_result AS ( SELECT Date, Child, total_sweets, RANK() OVER ( PARTITION BY Date ORDER BY total_sweets DESC ) AS rank_num FROM cumulative_stat ) SELECT Date, Child, total_sweets FROM rank_result WHERE rank_num = 1 ORDER BY Date;
代码说明:
- 第一层CTE通过
SUM() OVER()窗口函数,避免了传统写法的自连接,直接计算每个孩子的逐日累计吃糖数 - 第二层CTE通过
RANK()窗口函数做单日维度的排名,该函数会给相同累计值的记录相同排名,不会出现并列时空缺名次的问题,保证并列第一的记录全部被保留 - 最后过滤排名为1的记录即可得到目标结果
不支持窗口函数的旧版数据库写法(以MySQL 5.x为例)
如果使用版本较旧、不支持窗口函数的数据库,可以通过关联子查询实现相同逻辑:
-- 注意替换下方sweets_table为你实际使用的表名 SELECT t1.Date, t1.Child, (SELECT SUM(t2.`Sweets eaten`) FROM sweets_table t2 WHERE t2.Child = t1.Child AND t2.Date <= t1.Date) AS total_sweets FROM sweets_table t1 WHERE 0 = ( SELECT COUNT(DISTINCT cum_val) FROM ( SELECT SUM(t3.`Sweets eaten`) AS cum_val FROM sweets_table t3 WHERE t3.Date <= t1.Date GROUP BY t3.Child ) t_cum WHERE t_cum.cum_val > ( SELECT SUM(t4.`Sweets eaten`) FROM sweets_table t4 WHERE t4.Child = t1.Child AND t4.Date <= t1.Date ) ) ORDER BY t1.Date;
该写法通过多层子查询先计算每个孩子的累计值,再判断当前孩子的累计值是否比当日其他所有孩子的累计值都高,从而筛选出排名第一的记录,缺点是大数据量下执行效率低于窗口函数写法。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

