实际开发中,数据是存储在多张表中的,我们需要将多张表联合起来,查询出数据,就叫 连接查询 或者叫 跨表查询

SQL语法版本

  • SQL 92 语法 (1992 年出现)

例如:

  1. select p.name, j.name from person p, job p where p.id = j.id;
  2. select 1字段, 2字段 from 1 2 where 条件1 and 条件2;
  • SQL 99 语法(1999年出现)

    优点: 将表之间的连接 拎出来, 结构清晰,如果对结果不满意,再到后面追加 where 条件过滤

select p.name, p.jobId , j.job_name, j.id from person p join job_post j on p.jobId = j.id;

// 上面一种写法, 是 join 前面省略了 inner
select p.name, p.jobId , j.job_name, j.id from person p inner join job_post j on p.jobId = j.id;

select 表1字段, 表2字段 from 表1 join 表2 on 条件1 where 条件2;

连接分类

1. 内连接

内连接中,有一个 inner 关键字, inner join , 其中 inner 可以省略, 上面的 SQL语法版本 有示例

1.1 等值连接

问题1: 多张表连接查询,若没有任何条件限制,会发生什么?

小知识点:

  1. 在进行多表连接查询的时候,尽量给表起一个别名,可读性高,效率高; 有可能 A表有name字段, B表也有name字段,此时,查询的时候,如果不给别名,就不知道用哪个值了
select a.name, b.name from A a, B b;
// 没有加限制条件
select p.name, p.jobId, j.id, j.job_name from person p, job_post j;

person - 人员表 有 16条记录
job_post - 职位表 有14条记录

正常来说, 一个人,对应职位表里面一个职位, 那么查询出来的 还是 16条记录,但是,我们执行上面的SQL以后,会发现,有 224条记录, 怎么来的 16 *14 =224
image.png
直接将左边的每一条记录 和右边每一条记录 都匹配一次, 我们发现, 上面左边的人员表和右边的职位表,根本匹配不上

结论:
若两张表进行连接查询的时候, 不加条件限制, 则查询出来的结果是 两张表记录的条数 的乘积, 这种现象称为 “笛卡尔积”, 为了避免这种情况,应在两张表进行连接查询的时候,添加限制条件

还是上面的案例,加入限制条件
以下语法属于: SQL 92 语法 内连接的等值连接

select p.name, p.jobId, j.id, j.job_name from person p, job_post j where p.jobId = j.id;

SQL 99 语法 内连接的等值连接

select p.name , p.jobId, j.id, j.job_name from person p join job_post j on p.jobId = j.id;

image.png
注意: 现在虽然查询的记录已经符合要求, 16条, 但是查询的次数并没有变少,仍旧是 2张表的乘积 = 56, 只是显示出来的结果都事有效记录,16条

1.2 非等值连接

案例2: 找出每一个员工对应的工资等级, 要求显示 员工名,工资,工资等级
分析:
员工表 — person 有 name 和salary
薪资等级表 — salgrade 有等级 grade

image.png
员工表-图-1

image.png
薪资等级表-图-2

薪资等级是一个范围 类似 [1000, 3000] 那么就用到了 between xxx on xxxx
员工表中的 salary 在 区间范围内, 对应一个等级 salgrade

// SQL 99语法  使用 between and 设置区间
select p.name, p.salary, s.grade, s.losal as '最低薪资', s.hisal as '最高薪资' from person p join salgrade s on p.salary between s.losal and s.hisal;

// 使用 >= <=写法
select p.name, p.salary, s.grade, s.losal as '最低薪资', s.hisal as '最高薪资' from person p join salgrade s on p.salary >= s.losal and p.salary<= s.hisal;



// SQL 92语法 使用 where 加限定条件
select p.name, p.salary, s.grade, s.losal as '最低薪资', s.hisal as '最高薪资' from person p, salgrade s where p.salary between s.losal and s.hisal;

image.png

1.3 自连接

案例3: 找出每个员工的上级领导,要求显示员工名和对应的领导名

之前的案例,没有添加 leaderid,下面的表,新加的属性,重新造的数据,与前面的示例无关了

image.png
员工表-图

// SQL 99语法
select p.name '员工名称' , l.name as '领导名' from person p inner join person l on p.leaderid = l.id; 

// SQL 92语法
select p.name '员工名称' , l.name as '领导名' from person p, person l where p.leaderid = l.id;

image.png
上面有15条记录, 但是这个查询出来只有 14条,注意,李明 是没有 leaderid 的 所以,是不会被匹配,这个李明应该是最大的领导

2. 外连接

2.1 左外连接

很简单的理解, A 和B两张表, 左外连接,就是 join 以join左边的表为基础, 右边的表映射过来,左边的表数据可以完全展示,右边的表 不一定

select p.name, d.deptname as '部门名称' from  dept d left join person p on p.depId = d.id;

上面的 left join 表示 以 join 左边的表为基础 将右边的表的数据都映射过来(关联过来) , 左边表 dept 部门表,完全显示, 右边的表 人员表 Person 不一定完全显示

2.2 右外连接-右连接

右外连接 和 右连接 是一回事,不同的叫法


示例4:** 找出每个员工对应的部门名称,要求部门名称全部显示

// 这个语句,只是将 员工对应的部门全部都显示,但是部门不止这些
select p.name, d.deptname as '部门名称' from person p join dept d on p.depId = d.id;

image.png

查看一下部门表

select * from dept;

image.png
实施部和工程部, 对于 示例4** **的要求来说,并没有达到,也就是说 部门名称还没有 完全显示

正确的SQL
此示例是 外连接中的右外连接

// SQL 99语法
select p.name, d.deptname as '部门名称' from person p right join dept d on p.depId = d.id;

// outer 可以省略
select p.name, d.deptname as '部门名称' from person p right outer join dept d on p.depId = d.id;

image.png

左边表-人员表 person,没有匹配到的部门名称 以null 进行匹配, 右边的部门表 -dept 完全展示

示例5: 找出每个员工对应的领导名,要求显示所有员工

分析:

每个员工—person表
领导名, 领导也是公司员工 也是 person 表
显示所有员工, 那就是 外连接, 因为有的员工,比如 老板,他就没有上级领导,他就是最大的

// 这是左外连接   也可以写成右外连接的形式
select p.name as '员工名', l.name as '领导名' from person p left join person l on p.leaderid = l.id;

select p.name as '员工名', l.name as '领导名' from person l right join person p on p.leaderid = l.id;

image.png

总结:

  1. 左外连接 left join 就是以join 左边的表为主, 左边的表A完全显示, B表是否都显示,不一定
  2. 右外连接 right join 就是以 join 右边的表为主, 右边的表完全显示, 左边表的数据不一定都显示
  3. 对于 左连接或者右连接, 没有匹配到的数据 会以null 显示
  4. 任何一个左连接都可以写成右连接, 同样,任何一个右连接也可以写成左连接
  5. 外连接的 outer ,以及内连接的 inner 可以省略不写
  6. 区分SQL是内连接还是外连接, 就是依靠SQL中有没有 left 或 right, 加上inner 和outer 代码可读性强

如何区分外连接和内连接?

就看语法中,有没有 left 或者 right 关键字, 有的话 就是 外连接, 没有就是内连接

内连接和外连接的区别

  • 内连接: A表和B表能够完全匹配的记录,都查询出来
  • 外连接: A表和B表能够匹配的记录查询出来之外,还将其中一张表的记录,无条件的查询出来,对方没有匹配的记录,会自动模拟出null 与之匹配,这种就是外连接

外连接的查询结果条数 >= 内连接的查询结果条数

3. 全连接

多张表查询

案例6: 找出每个员工对应的部门名称, 以及该员工对应的薪资等级, 要求显示员工名, 部门名, 工资等级

分析:
每个员工—对应 person 表
每个员工的部门 — 对应 dept 部门表
薪资等级 — 对应 salgrade 薪酬范围表

员工的 deptId 对应 dept 表中的 id
员工的 薪资 salary 对应属于 salgrade的 losal 和 hisal 区间
select p.name, p.salary, d.deptname from
person p left join dept d on p.depId = d.id;

select p.name, p.salary, d.deptname, s.grade from
person p left join dept d on  p.depId = d.id
left join salgrade s on
p.salary between s.losal and s.hisal;

image.png
这个 始终是以 person 为主的, peron表有15条记录 最终通过连接查询, 仍旧返回15条记录

多张表进行连接,格式

select 
            XXXXX
from
            a表
join
            b表
on
            a.的条件 = b的条件
join
            c表
on
            a的条件 = c的条件

文字描述:
a表和 b表进行连接之后, a表再和c表进行连接