总结放前面:
FROM子句
JOIN ON条款
WHERE子句
GROUP BY子句
HAVING子句
SELECT子句
ORDER BY子句
LIMIT条款
在多表联接查询时,on先于where运行。
1. 语法及运行顺序
语法顺序
SELECT <字段列表>
FROM <左表>
<连接方式>INNER|LEFT|RIGHT JOIN <右表>
ON <连接条件>
WHERE <过滤条件>
GROUP BY <分组字段>
HAVING <包含条件>
ORDER BY <排序方式>
LIMIT <限制行数>
执行顺序
FROM子句
JOIN ON条款
WHERE子句
GROUP BY子句
HAVING子句
SELECT子句
ORDER BY子句
LIMIT条款
在多表联接查询时,on先于where运行。on条件生成笛卡尔积临时表,不论on后面的条件是什么,都会返回left join左侧的记录或者right join右侧的记录。
where是对生成的临时表进行过滤,这时就没有join联合的意义了,join联合的操作已经运算之后,where对整表进行过滤。
2. 新建简单的示例表
create table student
(
id int not null,
name varchar(10) not null,
primary key(id)
);
insert into student (id,name) values
(1,'aaa'),
(2,'bbb'),
(3,'ccc'),
(4,'ddd'),
(5,'eee'),
(6,'fff');
create table score
(
id int not null,
score int not null,
primary key(id)
);
insert into score (id,score) values
(3,77),
(4,88),
(5,99),
(7,100);
student表内容 score表
2.1. inner join 情况下
select * from student t inner join score c on t.id=c.id;
加入 on 条件
select * from student t inner join score c on t.id=c.id and t.id!=3 and c.id!=4;
结果:
加入where条件
发现,在inner join情况下,on和where的作用效果一致
2.2. left join 情况下
select * from student t left join score c on t.id=c.id ;
加入on条件
select * from student t left join score c on t.id=c.id
and t.id!=3
and c.id!=4;
我们会发现,在left join条件下,筛选条件仅仅对右表产生作用。t.id!=3对左表t没有影响。
并且因为join的条件为左右表的id相同(t.id=c.id),t.id!=3 相当于c.id!=3。
所以笛卡尔积中右表对应id为3,4的数据都为null
再来看看如果改为where会产生什么效果
加入where条件:
select * from student t left join score c on t.id=c.id
where t.id!=3
and c.id!=4;
结果为:
可以发现,where条件对前面联结的结果进行了过滤,将t=3,c=4的记录过滤掉了。
好奇的是,为什么id为1,2,6的数据也没有了呢?
因为!=会自动将null给过滤掉。这里的c!=4过滤掉了c为null的记录
如果想显示空值数据,需要显式列出:
select * from student t left join score c on t.id=c.id
where (t.id!=3 and c.id !=4) or c.id is null;
结果为:
注意:where是对最后的运算结果进行过滤,所以如果将c.id is null 改为t.id is null,结果还是只有id为5的一行记录。
2.3. right join情况下
select * from student t right join score c on t.id=c.id ;
加入 on条件
select * from student t right join score c on t.id=c.id
and t.id!=3
and c.id !=4;
同样的,可以看出右连接时,过滤条件仅对左表产生影响。
on t.id=c.id and t.id!=3 and c.id !=4 实际效果为过滤了左表中id为3及4的数据,显示为null
加入where条件
select * from student t right join score c on t.id=c.id
where t.id!=3
and c.id !=4;