如何获取仅含最新创建记录的1:n表关联查询结果?
解决按分组取最新记录并关联子表的问题
这个需求其实挺典型的——要先锁定每组(id_something+date_day)里created最新的那条主表记录,再把它和子表的所有关联数据拉出来。我给你两个通用的、非Oracle专属的方案,性能和可读性都不错:
方案一:用窗口函数(推荐,性能最优)
窗口函数是处理这类分组取TOP N场景的利器,逻辑清晰而且效率高。我们先给主表的每条记录按分组排序,标记出每组里最新的那条,再关联子表:
WITH ranked_one AS ( SELECT *, -- 按id_something+date_day分组,组内按created倒序排,最新的记录行号为1 ROW_NUMBER() OVER (PARTITION BY id_something, date_day ORDER BY created DESC) AS rn FROM one ) -- 只取每组行号为1的记录,再关联表二的所有对应数据 SELECT r.id, r.id_something, r.date_day, r.created, t.id_one, t.foo, t.bar FROM ranked_one r LEFT JOIN two t ON r.id = t.id_one WHERE r.rn = 1;
如果你的业务允许同一组存在多条created完全相同的“并列最新”记录,可以把ROW_NUMBER()换成RANK(),这样会保留所有并列的记录。
方案二:子查询筛选最新记录(兼容老版本数据库)
如果你的数据库不支持CTE(比如MySQL 5.7及以前),可以用子查询先找出每组的最大created值,再反向匹配主表记录,最后关联子表:
SELECT o.id, o.id_something, o.date_day, o.created, t.id_one, t.foo, t.bar FROM one o LEFT JOIN two t ON o.id = t.id_one WHERE (o.id_something, o.date_day, o.created) IN ( -- 先算出每组的最新created时间 SELECT id_something, date_day, MAX(created) FROM one GROUP BY id_something, date_day );
这个方案要注意:如果同一组有多个记录的created等于最大值,会返回所有这些记录;如果业务上每组只会有一条最新记录,这个写法完全没问题。
为什么你之前的尝试没成功?
你提到用GROUP BY只能返回单行,是因为GROUP BY会把每组合并成一条记录,没法保留子表的多对一关联数据。我们的思路是先筛选出符合条件的主表记录,再关联子表,这样就能保留子表的所有对应键值对了。
另外,给主表的(id_something, date_day, created)字段建个联合索引,能让这两个方案的性能大幅提升,尤其是数据量大的时候。
内容的提问来源于stack exchange,提问作者Trollwut
相关产品推荐
相关产品推荐

