如何编写关联partners与tasks的SQL,返回所有合作伙伴及其最近到期任务?
现有SQL的核心问题
- 左连接失效:将
tasks.data >= 2021的过滤条件写在WHERE子句中,会直接把左连接生成的、任务字段为NULL的无匹配合作伙伴记录过滤掉,无法保留没有任务的合作伙伴 - 筛选逻辑错误:直接按
tasks.code分组取记录,没有对组内任务按日期排序,无法精准定位“日期大于等于参考值、距离参考日期最近”的任务,最终结果依赖数据库的默认存储顺序,和预期不一致 - 分组不规范:在未开启宽松分组模式的数据库中,直接SELECT非聚合的任务字段会触发语法报错,返回的字段值也无法保证正确
正确实现方案
整体实现思路:
- 先预过滤所有满足“日期大于等于参考值”的任务,避免过滤逻辑影响左连接结果
- 对每个合作伙伴code下的合格任务按日期升序排序,仅取排名第一的记录——也就是离参考日期最近的那条任务
- 通过左连接关联合作伙伴表,对无匹配任务的字段做空值兜底,标记为
No Task
通用实现(支持窗口函数的数据库通用)
-- 参考日期值可根据实际业务需求替换,示例匹配测试场景的2021参考值 WITH qualified_tasks AS ( SELECT code, comment, data, -- 按日期升序排序,同合作伙伴下日期最小的(离参考日期最近的)排名为1 ROW_NUMBER() OVER ( PARTITION BY code ORDER BY data ASC ) AS rn FROM tasks WHERE data >= 2021 ) SELECT p.id, p.code, p.name, -- 无匹配任务时兜底显示No Task COALESCE(qt.comment, 'No Task') AS task_comment, qt.data AS task_data FROM partners p LEFT JOIN qualified_tasks qt ON p.code = qt.code AND qt.rn = 1 ORDER BY p.id;
低版本兼容实现(不支持窗口函数的数据库可用)
通过关联子查询直接匹配每个合作伙伴下满足条件的最小日期值,效果和窗口函数实现完全一致
SELECT p.id, p.code, p.name, COALESCE(t.comment, 'No Task') AS task_comment, t.data AS task_data FROM partners p LEFT JOIN tasks t ON p.code = t.code AND t.data = ( -- 查找同合作伙伴下,大于等于参考值的最小日期(距离参考日期最近) SELECT MIN(data) FROM tasks WHERE code = p.code AND data >= 2021 ) ORDER BY p.id;
执行以上SQL的输出完全匹配预期结果:
1 , 222, M, m, 2021 2 , 333, F, f, 2021 3 , 555, F-m, No Task
内容的提问来源于stack exchange,提问作者Andrei
相关产品推荐
相关产品推荐

