MySQL多表关联查询问题:获取所有球员及下一次训练信息
解决方案:获取所有球员信息及最近未来训练日期
我完全理解你的需求——要拿到每一位球员的完整信息,包括他们当前日期之后的最近一次训练(如果有的话),就算没有未来训练,也不能把球员信息漏掉。你之前的SQL之所以达不到要求,核心问题出在这两点:
- 用了
WHERE training.start_date > CURRENT_DATE过滤,这会直接把LEFT JOIN后training相关字段为NULL的球员(也就是没有未来训练的)排除掉,因为NULL > CURRENT_DATE的结果是UNKNOWN,WHERE子句只会保留条件为TRUE的行; - GROUP BY的用法不规范,会导致查询结果出现不确定的字段值(除非你用的是MySQL的非严格模式)。
下面给你两种可行的解决方案,都能满足你的需求:
方法一:使用窗口函数(推荐,可读性和性能都不错)
窗口函数可以很方便地给每个球员的未来训练排序,直接取最近的那一条:
SELECT t.id_team, p.id_player, tr.id_training, p.name AS player_name, p.age, tr.start_date FROM Player p -- 关联球员所属球队 JOIN Team_Player tp ON p.id_player = tp.id_player JOIN Team t ON tp.id_team = t.id_team -- 左关联筛选出的每个球员的最近未来训练 LEFT JOIN ( SELECT id_training, id_player, start_date, -- 按球员分组,训练日期升序排序,最近的训练排第1 ROW_NUMBER() OVER (PARTITION BY id_player ORDER BY start_date ASC) AS rn FROM Training -- 只筛选当前日期之后的训练 WHERE start_date > CURRENT_DATE ) tr ON p.id_player = tr.id_player AND tr.rn = 1 -- 按球员ID排序,方便查看 ORDER BY p.id_player;
方法二:使用关联子查询
如果你的数据库不支持窗口函数(比如一些旧版本的数据库),可以用关联子查询来获取每个球员的最近未来训练日期,再关联Training表:
SELECT t.id_team, p.id_player, tr.id_training, p.name AS player_name, p.age, tr.start_date FROM Player p JOIN Team_Player tp ON p.id_player = tp.id_player JOIN Team t ON tp.id_team = t.id_team -- 左关联训练表,只匹配当前球员最近的未来训练 LEFT JOIN Training tr ON p.id_player = tr.id_player AND tr.start_date = ( -- 子查询获取当前球员的最近未来训练日期 SELECT MIN(start_date) FROM Training WHERE id_player = p.id_player AND start_date > CURRENT_DATE ) ORDER BY p.id_player;
这两种方法都会返回你期望的结果:没有未来训练的球员,对应的id_training和start_date会显示为NULL,同时保留所有球员的基础信息和所属球队信息。
内容的提问来源于stack exchange,提问作者Erwan
相关产品推荐
相关产品推荐

