SQL查询需求:按客户筛选对应最高营收的日期(修正现有查询)
解决每个客户最高营收对应日期的筛选问题
嗨,我懂你现在的困扰——之前的查询只能算出每个客户每天的最高营收,但你真正要的是定位到每个客户营收最高的那一天(或几天)。这里给你两种常用的解决方案,适配不同的数据库和场景:
方案1:使用窗口函数(推荐,支持PostgreSQL、MySQL 8+、SQL Server等)
窗口函数是处理这类分组Top N问题最简洁的方式,根据你是否需要保留并列最高的记录,可以选两种函数:
场景A:只取每个客户最高营收的一条记录(若有并列,按日期排序取其一)
用ROW_NUMBER()给每个客户的记录按营收降序、日期升序(或降序)编号,然后取编号为1的记录:
WITH ranked_revenue AS ( SELECT customer_id, revenue_date, daily_revenue, ROW_NUMBER() OVER ( PARTITION BY customer_id ORDER BY daily_revenue DESC, revenue_date ASC ) AS rn FROM customer_revenue ) SELECT customer_id, revenue_date, daily_revenue FROM ranked_revenue WHERE rn = 1;
PARTITION BY customer_id:按客户分组ORDER BY daily_revenue DESC:每组内按营收从高到低排序- 额外加
revenue_date ASC是为了当营收相同时,取最早的那一天(你也可以改成DESC取最晚的)
场景B:保留每个客户所有营收并列最高的日期
如果同一个客户有多天营收都是最高值,用RANK()函数可以把这些记录都保留下来:
WITH ranked_revenue AS ( SELECT customer_id, revenue_date, daily_revenue, RANK() OVER ( PARTITION BY customer_id ORDER BY daily_revenue DESC ) AS rnk FROM customer_revenue ) SELECT customer_id, revenue_date, daily_revenue FROM ranked_revenue WHERE rnk = 1;
和ROW_NUMBER()不同,RANK()会给并列的记录分配相同的排名,所以所有最高营收的日期都会被筛选出来。
方案2:子查询关联(兼容老版本数据库,如MySQL 5.x)
如果你的数据库不支持窗口函数,可以先查询每个客户的最高营收值,再关联原表找到对应的日期:
SELECT cr.customer_id, cr.revenue_date, cr.daily_revenue FROM customer_revenue cr JOIN ( SELECT customer_id, MAX(daily_revenue) AS max_revenue FROM customer_revenue GROUP BY customer_id ) cr_max ON cr.customer_id = cr_max.customer_id AND cr.daily_revenue = cr_max.max_revenue;
这个方法同样会保留所有营收等于最高值的日期,和RANK()的效果一致。
注意:如果你的表中有重复的(customer_id, revenue_date)记录,可能需要根据实际情况加
DISTINCT去重。
内容的提问来源于stack exchange,提问作者michaelg




