Skip to content
Leo的技术分享
Go back

SQL JOIN 的使用

由于工作需要,现在也开始写一些复杂一点的 sql 了。由于之前对于 joinwhere 关键字的使用一直有疑惑,故写一篇文章整理一下,算是对 sql 中各种表联结使用的一个总结。

SQL JOIN 的作用

sql 关键字 unionintersect 属于以行方向为单位的集合运算,进行这些集合运算时,会导致记录行数的增加或减少。 关键字 join 则是属于列方向的运算,将其他表中的列添加过来。我们称这种操作为联结。 sql 联结根据其用途可以分为多种,这里主要讲述内联结与外联结。

INNER JOIN

内联结,inner join,是使用最广泛的联结运算。我们以例子来说明内联结的含义。

student 表结构与记录以下:

student_idstudent_name
1Leo
2Lee
3Hao

score 表结构与记录以下:

student_idstudent_score
189
295

可以看到 student_id 列存在于 student 表和 score 表,其他列则只存在于一张表。可以将 student_id 列作为桥梁,将两表满足同样条件的列汇集到同一结果之中,这就是联结运算。

可以看到,学生 Leo 的 id 为 1,分数在 score 表,Leo 的分数为 89 分。学生 Lee 的 id 为 2,分数为 95。学生 Hao 的 id 为 3,但 score 表中没有 Hao 的分数。

使用 inner joinstudent 表和 score 表进行联结,sql 以下所示:

select st.student_id, st.student_name, sc.student_score
from student st
       inner join score sc on st.student_id = sc.student_id;

执行 sql 结果如下所示。

student_idstudent_namestudent_score
1Leo89
2Lee95

关于 inner join 的使用,有几点需要注意的。

from 子句使用 inner join ,将两张表联结起来。

on 子句是联结的条件,例如我们使用 student_id 作为联结条件:

on st.student_id = sc.student_id

select 子句用于指定提取哪些列。

如果我们只想看查 student_id 为 1 的情况,可以继续使用 where 子句。

select st.student_id, st.student_name, sc.student_score
from student st
       inner join score sc on st.student_id = SC.student_id
where st.student_id = 1;

执行结果以下:

student_idstudent_namestudent_score
1Leo89

OUTER JOIN

外联结,outer join,与内联结一样,也是通过 on 子句将两张表联结起来,只是结果有所不同。

为了说明外联结与内联结的不同,我们将上面内联结的例子转换成外联结,看下执行结果。

select st.student_id, st.student_name, sc.student_score
from student st
       left outer join score sc on st.student_id = sc.student_id;

执行结果如下表所示:

student_idstudent_namestudent_score
1Leo89
2Lee95
3Hao

与内联结相比,外联结的不同点在于结果的行数不一样。内联结执行结果有 2 条记录,外联结却有 3 条记录,增加的 1 条记录是 student_id 为 3 的学生 Hao。虽然 score 表并没 student_id 为 3 的成绩,但执行结果仍然把这条记录提取出来了。在实际应用中,如果我们想生成固定行数的数据时,就需要使用外联结。

内联结只会提取同时存在于两张表中的数据,因此 Hao 学生记录并不会出现。对于外联结来说,只要数据存在于某一张表中,就能够提取出来。

同时我们也看到,由于 score 表中并没有 Hao 学生的成绩,所以执行结果该字段为 null。

外联结可以指定哪张表为主表,查询结果会包含主表的所有记录。使用 left 时 from 子句中写在左侧的表是主表,使用 right 时右侧的表是主表。上述外联结代码使用 left ,因此左侧的 student 表是主表。

我们也可以使用 right 对代码进行改写,效果完全一样。

select st.student_id, st.student_name, sc.student_score
from score sc
       right outer join student st on st.student_id = sc.student_id;

至于使用 left 或者 right,使用哪一个都可以,通常来说,使用 left 的情况多一些。

CROSS JOIN

交叉联结,cross join,是指对联结的表进行笛卡尔积运算。

我们对 student 表和 score 表进行交叉联结:

select st.student_id, st.student_name, sc.student_id, sc.student_score
from student st
       cross join score sc;

查询结果如下:

student_idstudent_namestudent_idstudent_score
1Leo189
2Lee189
3Hao189
1Leo295
2Lee295
3Hao295

进行交叉联结时,无法使用内联结和外联结中所使用的 on 子句,这是因为交叉联结是对两张表中的全部记录进行交叉组合,结果记录数是两张表中行数的乘积。student 表包含 3 条记录,score 表包含 2 条记录,故交叉联结结果包含 3 * 2 = 6 条记录。

内联结是交叉联结的一部分,“内”可以理解为“包含在交叉联结结果中的部分”。相反,外联结的“外”可以理解为“交叉联结结果之外的部分”。

在实际应用中,交叉联结使用较少。一是其结果没有实用价值,二是由于结果太多,需要花费大量的运算时间。

过时的语法

上述 sql 代码中,我们使用 inner joinouter join 等联结关键字符合 sql 标准,但实际开发中,却经常会碰到使用 where 关键字来实现联结。

将上面我们实现内联结的 sql 代码替换成使用 where 来实现:

select st.student_id, st.student_name, sc.student_score
from student st, score sc
where st.student_id = sc.student_id and st.student_id = 1;

执行结果以下:

student_idstudent_namestudent_score
1Leo89

这样的书写方式的查询结果与标准语法的查询结果相同,但这种语法不仅已过时,还存在其他问题:

虽然不建议使用过时的语法,但我们仍然需要具备阅读这些过时语法代码的能力 :)

参考资料


Share this post on:

Previous Post
Oracle / PL SQL: CURSOR FOR LOOP 使用
Next Post
贝叶斯公式学习笔记