left join 执行原理

create table class
(

1
2
class_id varchar(10),
class_name varchar(50)

)

insert into class values (1,'语文');
insert into class values (2,'数学');
insert into class values (3,'英语');

create table score
(

1
2
3
class_id varchar(10),
Student_id varchar(10),
Score int

)

insert into score values (1,'A001',90);
insert into score values (2,'A001',95);
insert into score values (1,'A002',80);
insert into score values (2,'A002',85);
insert into score values (1,'B001',88);

select * from class
select * from score

--一个课程表,一个成绩表
--表数据分布是
--成绩表:有三个学生A,B,C,
--A,B都有语文和数学成绩,
--C只有语文成绩;
--A,B,C都没有英语成绩,
--课程表,有语文,数学,英语三门课程,没有“体育”这门课程

--如果你对left join足够熟悉的话,先不要看结果,是否可以直接说出下面查询的结果

select * from class A left join score B on A.class_id=B.class_id and A.class_name='语文'
select * from class A left join score B on A.class_id=B.class_id and A.class_name='数学'
select * from class A left join score B on A.class_id=B.class_id and A.class_name='英语'
select * from class A left join score B on A.class_id=B.class_id and A.class_name='体育'

select * from class A left join score B on A.class_id=B.class_id
where A.class_name='语文'

select * from class A left join score B on A.class_id=B.class_id
where A.class_name='数学'

select * from class A left join score B on A.class_id=B.class_id
where A.class_name='英语'

select * from class A left join score B on A.class_id=B.class_id
where A.class_name='体育'

--其实结果我不想贴了,以后再整理,如果结果跟你预期的不一样,
--或者你对查询结果感到疑惑,下面就是对上面结果的解释

/过滤条件在on中时*/

--不管on中的条件如何写,左连接首先要得到左边的所有的行
--对于右边的表,如果满足连接条件,则输出值,如果不满足条件,则返回null
--也就是说,on中的过滤条件(比如 on leftTable.id=rightTable.id and leftTable.colName='*'),
--是作为左外连接的连接条件,而不是过滤条件
--左边表的数据是要全部输出的,做联接的时候,
--抽取符合(leftTable.colName='*')条件的的左边的数据行,跟右边的表做连接,输出结果
--不符合(leftTable.colName='*')条件的数据行,输出左边表,右边表为null值,输出结果
比如这个sql:
select * from class A left join score B on A.class_id=B.class_id and A.class_name='英语'

查询过程是这样的:
找出A表的第一条数据,判断是否符合class_name='英语'
如果符合,则跟右表做,输出A表+B表的行(当然存在B表中可能没有相关ID的英语成绩,那么B表也可以输出null)
如果不符,直接输出A表中的行,B表中的行直接为null

从这个过程可以看出,on中的等值条件只是影响left join产生结果集的过程,并不参与数据的过滤
A表总是将其所有的值输出的(不管过滤条件是啥,不管B表是否存在相关信息)

/过滤条件在where中时**/

--但是过滤条件写在where中(on leftTable.id=rightTable.id where leftTable.colName='*')时,
--是作为对左边表的“过滤条件”,就意味着先根据where(where leftTable.colName='*')条件过滤左边的表
--然后将过滤后的结果跟右边的表做左联接连接