MySQL左关联获取最新右表记录,无数据时显示NULL
解决方案:获取左表全量记录并关联右表最新数据
原查询问题分析
你的原查询存在两处关键问题:
- 关联
tally表时使用了未定义的别名tb(子查询内的别名无法作用到外层连接条件); - 子查询的逻辑错误,导致左连接的过滤条件变相成为内连接规则,丢失了无关联记录的
bill行(比如billId=1)。
正确实现(MySQL 8.0+ 窗口函数方案)
利用MySQL 8.0支持的ROW_NUMBER()窗口函数,可以高效筛选每个bill对应的最新tally记录,同时保证左表全量输出:
WITH ranked_tallies AS ( SELECT tb.billId, t.countYes, t.countNo, -- 按bill分组,每组内按创建时间倒序排名,最新记录排第1 ROW_NUMBER() OVER (PARTITION BY tb.billId ORDER BY t.created DESC) AS rn FROM tally_bill tb JOIN tally t ON tb.tallyId = t.id ) SELECT b.id AS billId, b.description, b.extId, rt.countYes, rt.countNo FROM bill b LEFT JOIN ranked_tallies rt ON b.id = rt.billId AND rt.rn = 1;
逻辑说明
- CTE子查询(ranked_tallies):
- 关联中间表
tally_bill和数据tally表,获取所有bill对应的tally记录; - 通过窗口函数
ROW_NUMBER()给每个bill分组内的tally记录按created降序排名,最新的记录会被标记为rn=1。
- 关联中间表
- 主查询:
- 从
bill表左连接到CTE结果,只匹配排名为1的记录(即每个bill的最新tally数据); - 左连接保证即使没有对应
tally记录的bill(比如id=1)也会保留在结果中,对应的统计字段自动填充为NULL。
- 从
结果验证
执行上述查询后,会得到与你期望完全一致的输出:
billId description extId countYes countNo 1 Some descr... SB 123 null null 2 Another de... SB 124 5 8 3 Third desc... SB 125 4 3
兼容写法(无CTE版本)
如果不习惯使用CTE,也可以将逻辑嵌套为子查询:
SELECT b.id AS billId, b.description, b.extId, rt.countYes, rt.countNo FROM bill b LEFT JOIN ( SELECT tb.billId, t.countYes, t.countNo, ROW_NUMBER() OVER (PARTITION BY tb.billId ORDER BY t.created DESC) AS rn FROM tally_bill tb JOIN tally t ON tb.tallyId = t.id ) rt ON b.id = rt.billId AND rt.rn = 1;
内容的提问来源于stack exchange,提问作者niko
相关产品推荐
相关产品推荐

