SQL实现:筛选指定构建任务并按base_id保留最小queue_time单行
解决方案:筛选并分组获取指定条件的构建任务
嘿,这个需求可以拆成两步来实现——先精准筛选出符合要求的pending任务,再在这些任务里按base_id提取每组中queue_time最小的那一行。下面给你两种实用的方案,适配不同的数据库版本:
方案一:用窗口函数(推荐,适合支持SQL:2003及以上的数据库,比如PostgreSQL、MySQL 8.0+、SQL Server等)
窗口函数是最简洁直观的方式,先通过CTE筛选出符合条件的任务,再给每组base_id的任务按queue_time排序,取排序第一的行:
WITH eligible_pending_tasks AS ( SELECT *, -- 按base_id分组,每组内按queue_time升序排,生成行号 ROW_NUMBER() OVER (PARTITION BY base_id ORDER BY queue_time ASC) AS row_num FROM build_tasks WHERE status = 'pending' -- 确保当前base_id下没有in-progress的任务 AND NOT EXISTS ( SELECT 1 FROM build_tasks bt_inner WHERE bt_inner.base_id = build_tasks.base_id AND bt_inner.status = 'in-progress' ) ) -- 只保留每组行号为1的记录(也就是queue_time最小的那行) SELECT * EXCEPT (row_num) -- 如果是MySQL,改成列出所有需要的列,去掉row_num FROM eligible_pending_tasks WHERE row_num = 1;
解释下关键部分:
NOT EXISTS子句用来排除那些base_id下存在in-progress任务的记录ROW_NUMBER()窗口函数给每个base_id组内的任务按queue_time从小到大编号,row_num=1就是每组最早进入队列的任务
方案二:用子查询关联(兼容旧版本数据库,比如MySQL 5.x)
如果你的数据库不支持窗口函数,可以先找出每个符合条件的base_id对应的最小queue_time,再通过关联原表获取完整行数据:
SELECT bt.* FROM build_tasks bt INNER JOIN ( -- 先筛选符合条件的base_id,并计算每个base_id的最小queue_time SELECT base_id, MIN(queue_time) AS earliest_queue_time FROM build_tasks WHERE status = 'pending' AND NOT EXISTS ( SELECT 1 FROM build_tasks bt_inner WHERE bt_inner.base_id = build_tasks.base_id AND bt_inner.status = 'in-progress' ) GROUP BY base_id ) AS min_queue_info ON bt.base_id = min_queue_info.base_id AND bt.queue_time = min_queue_info.earliest_queue_time WHERE bt.status = 'pending';
这个方案的逻辑是:先通过子查询得到每个合格base_id的最早队列时间,再把这个结果和原表关联,找到对应时间的完整任务记录。
内容的提问来源于stack exchange,提问作者Jordán David Nikolov
相关产品推荐
相关产品推荐

