SQL如何查询pesajes表中选手最后称重accepted为0的记录
问题背景
现有存储参赛选手称重记录的pesajes表,表结构及示例数据如下:
| id | championship | competitor | accepted | time |
|---|---|---|---|---|
| 1 | 18 | 1280 | 0 | 1370931202 |
| 2 | 18 | 1280 | 1 | 1370931784 |
| 3 | 18 | 1203 | 0 | 1370932502 |
| 4 | 18 | 870 | 1 | 1370934905 |
| 5 | 18 | 1203 | 0 | 1370961212 |
| 6 | 18 | 1100 | 0 | 1370984288 |
需求是筛选指定锦标赛下,选手最后一次称重记录accepted值为0的行,以上述示例为例,期望返回id为5、6的两条记录。
原有错误查询:
SELECT * FROM pesajes WHERE championship=18 and accepted=0 GROUP by id
该语句的问题是没有判断选手后续是否存在更新的称重记录,会错误返回选手早期未通过、后续已经称重通过的记录(比如示例中id=1的记录,对应选手1280最后一次称重已通过,不属于目标结果)。
正确实现方案
方案1:通用子查询关联写法(兼容所有主流SQL版本)
核心逻辑是先定位每个选手在指定锦标赛下的最后一次称重时间,再关联回原表取对应完整记录,最后筛选accepted为0的行:
SELECT p.* FROM pesajes p INNER JOIN ( -- 计算指定锦标赛下每个选手的最后一次称重时间 SELECT competitor, MAX(time) AS last_weigh_time FROM pesajes WHERE championship = 18 GROUP BY competitor ) t ON p.competitor = t.competitor AND p.time = t.last_weigh_time WHERE p.accepted = 0;
运行该语句在示例数据下只会返回id=5、6的记录,完全匹配需求:选手1280最后一次称重accepted=1、选手870最后一次称重accepted=1,都会被正确过滤。
方案2:窗口函数写法(支持MySQL8.0+、PostgreSQL、SQL Server2005+等新版本环境)
用窗口函数按选手分组、按称重时间倒序排名,直接取每个选手排名第一的最新记录做筛选,不需要自关联,逻辑更清晰:
WITH weigh_rank AS ( SELECT *, ROW_NUMBER() OVER ( PARTITION BY competitor ORDER BY time DESC, id DESC -- 加id倒序避免同时间戳下取错记录 ) AS rn FROM pesajes WHERE championship = 18 ) SELECT id, championship, competitor, accepted, time FROM weigh_rank WHERE rn = 1 AND accepted = 0;
注意事项
如果存在同一选手同一锦标赛下多条记录time值完全相同的极端场景,不管用哪种方案,都建议把id作为次级排序/关联判断条件,确保取到最新插入的那条记录作为最后一次称重结果,避免数据重复或错漏。
内容的提问来源于stack exchange,提问作者Nebur81
相关产品推荐
相关产品推荐

