SQL单列去重问题:按ID保留最大day值的唯一行
解决SQL中按ID保留最大day值行的去重问题
问题分析
你的原查询无法去重的核心原因是:当同一个ID存在多条day等于最大值的记录(且这些记录的score不同)时,WHERE day IN (...)会把所有这些行都筛选出来,而DISTINCT无法消除它们——因为这些行的score字段值不同,属于不同的记录。你需要的是每个ID仅保留一条day最大的记录,而非所有day等于最大值的记录。
解决方案
以下是几种通用且高效的实现方式,适用于不同版本的SQL数据库:
方法1:窗口函数ROW_NUMBER()(推荐,支持MySQL 8+、PostgreSQL、SQL Server等)
这是最灵活的方案,能精准控制每个ID取哪一行:
SELECT ID, score, day FROM ( SELECT ID, score, day, -- 按ID分组,每组内按day降序排序,给行编号 ROW_NUMBER() OVER (PARTITION BY ID ORDER BY day DESC) AS row_num FROM tableA ) AS temp -- 取每个组的第一行(即day最大的行) WHERE row_num = 1;
- 如果同一个ID有多条day为最大值的记录,且你想指定取score最大的那一行,只需修改排序规则:
ROW_NUMBER() OVER (PARTITION BY ID ORDER BY day DESC, score DESC) AS row_num
方法2:关联子查询(兼容MySQL 5.x等不支持窗口函数的版本)
通过子查询先获取每个ID的最大day,再关联原表筛选对应行:
SELECT a.ID, a.score, a.day FROM tableA a JOIN ( SELECT ID, MAX(day) AS max_day FROM tableA GROUP BY ID ) AS b ON a.ID = b.ID AND a.day = b.max_day;
- 如果同一个ID有多个max_day的记录,需要去重的话,可以结合聚合函数指定score的取值(比如取最大score):
SELECT a.ID, MAX(a.score) AS score, a.day FROM tableA a JOIN ( SELECT ID, MAX(day) AS max_day FROM tableA GROUP BY ID ) AS b ON a.ID = b.ID AND a.day = b.max_day GROUP BY a.ID, a.day;
方法3:窗口函数FIRST_VALUE()
利用窗口函数直接提取每个ID对应最大day的score:
SELECT DISTINCT ID, FIRST_VALUE(score) OVER (PARTITION BY ID ORDER BY day DESC) AS score, MAX(day) OVER (PARTITION BY ID) AS day FROM tableA;
原查询问题总结
原查询的逻辑是“筛选所有day等于任意ID最大day的行”,而非“每个ID仅取自己最大day的那一行”——这会导致当某个ID有多条max_day记录时,所有这些行都会被保留,最终出现重复ID的情况。
内容的提问来源于stack exchange,提问作者mapleleaf
相关产品推荐
相关产品推荐

