on和where是什么?
两者都是进行筛选过滤的
on: 决定 join 表的行“是否能关联”。 两个表中哪些行可以匹配(关联)
where: 对结果行做最终过滤。在 from 和 join 执行完成后,执行 where,对当前结果做条件行级过滤。
where 是“结果过滤条件”,on 是“关联阶段条件”
- 使用场景:where对查询结果根据where条件进行筛选过滤;on 在多表 join 场景下进行 on 条件进行筛选过滤
- 执行时机:on 和 where 同时存在的查询中,先执行on,后执行 where。on 先于 where 执行。先是 on 条件过滤,然后是 join 结果,最后 where 过滤。
inner join 和 left join
join 多表场景,mysql 会将 join on 的结果生成一张临时表,最后将临时表做 where 等条件过滤操作。on 比 where 更早起作用。
left join(左链接):会保留左表返回所有的行,即使在右表中没有匹配的行。 inner join(内连接):只返回两个表中 on 条件匹配的行
在不同 join 中的作用
inner join
inner join(要求两边都存在):查询过滤条件放在 on 中和 where 中是完全等价的。
执行引擎可能会将 on 条件和 where 条件放一起。注意:“结果集上等价,但执行顺序可能不同”。
left join
left join B on A.id = B.a_id
where B.x = 1;
left join B on A.id = B.a_id and B.x = 1;
如果要过滤整行数据,需要将 B.x = 1 放在where条件中,等A和B表 join on 完成之后再进行整行数据的筛选过滤。
如果仅仅是不想要B表的 B.x = 1 数据查询出来,但是A的数据还要保留,那么需要放在 on 条件中,保留A 行数据,B表相关字段为null。
case
A表
B表
| join | 查询场景 | sql | 结果 |
|---|---|---|---|
| left join | B表查询条件放在 on | select A.id as a_id, A.name, B.id as b_id, B.flag from A left join B on A.id = B.a_id and B.flag = 1 order by A.id; | B.flag = 1 只决定能不能 join 到 B。 A.id=3 没有匹配,仍然保留 |
| left join | B表查询条件放在 where | select A.id as a_id, A.name, B.id as b_id,B.flag from A left join B on A.id = B.a_id where B.flag = 1 order by A.id; | a3记录消失未返回。 |
| inner join | B表查询条件放在 on | select A.id as a_id, A.name, B.id as b_id, B.flag from A inner join B on A.id = B.a_id where B.flag = 1 order by A.id; | where和on结果完全一致 |
| inner join | B表查询条件放在 where | select A.id as a_id, A.name, B.id as b_id, B.flag from A inner join B on A.id = B.a_id and B.flag = 1 order by A.id; | where和on结果完全一致 |
反join场景
select *
from A
left join B
ON A.id = B.a_id
where B.a_id IS NULL;
执行语义:
- left join 匹配
- 没匹配到 → B.a_id = NULL
- where 过滤出「没匹配到的B」的A表数据