0.概述

作用:当所需要查询的数据分布在多张表上时,需要使用多表查询(连接查询)

方式:  1.SQL92多表查询        2.SQL99多表查询   

两种方式均可,其中SQL92书写方便阅读困难,SQL99书写较麻烦,但阅读很方便,而且符合逻辑(下文会体现),两种方式都有使用,所以都要学习。不过更推荐SQL99。

1.SQL92多表查询

笛卡尔积

笛卡尔积也称直积,两个集合XY的笛卡尓积表示为X × Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员。例如集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。

概念:在数据库中即为将多个表中的数据进行一一对应,所得到的结果为多表的笛卡尔积,结果数量为所有表的数量乘积。

select * from emp,dept;  --emp14条,dept4条  最后查询出14*4=56条数据

等值连接

概念:先做表的笛卡尔积,然后筛选,筛选条件为等值筛选

--查询员工姓名,工作,薪资(emp表)和部门名称(dept表)
select ename,job,sal,dname from emp,dept where emp.deptno=dept.deptno;
--可以直接在select子句中使用字段直接获取数据,但是效率较低,字段前加上名字。
--注意公共字段前面必须有表名
select emp.ename,emp.job,emp.sal,dept.dname from emp,dept where emp.deptno=dept.deptno;
--字段名较长时也可以给表使用别名
select e.ename,e.job,e.sal,d.dname from emp e,dept d where e.deptno=d.deptno; --最常见格式

不等值连接

概念:先做表的笛卡尔积,然后筛选,筛选条件为不等值连接

--查询员工姓名,工作,工资,工资等级
select e.ename,e.job,e.sal,s.grade from emp e,salgrade s where e.sal>=losal and e.sal<=hisal;

自连接

概念:自身与自身(两张相同的表)做表的笛卡尔积,然后进行筛选

--查询员工姓名,工作,工资及上级领导姓名
select e1.ename,e1.job,e1.sal,e2.ename from emp e1,emp e2 where e1.mgr=e2.empno;

外连接

左外连接         (+)放右侧   显示左边对应字段没有值的数据

--查询员工姓名,工作,薪资,部门名称以及没有部门的员工信息
select e.ename,e.job,e.sal,d.dname from emp e,dept d where e.deptno=d.deptno(+);

右外连接         (+)放左侧   显示右边对应字段没有值的数据

--查询员工姓名,工作,薪资,部门名称以及没有员工信息的部门
select e.ename,e.job,e.sal,d.dname from emp e,dept d where e.deptno(+)=d.deptno;

2.SQL99多表查询

注意:

  • 依然可以给表添加别名
  • 如果使用on或者using关键字对结果进行筛选必须使用inner join进行表与表的连接,其中inner可以省略
  • 外连接的outer关键字可以省略不写
  • 依然可以继续使用group by,having,order by

笛卡尔积

使用cross join关键字       select 内容 from 表名1 cross join 表名2

select * from emp cross join dept;  --56条

自然连接

使用natural join关键字     select 内容 from 表名1 natural join 表名2

特点:底层先笛卡尔积,然后按照所有的同名同值的字段自动进行等值筛选

select * from emp cross join dept;  --56条

缺点1:如果想按照部分字段进行筛选怎么办?

缺点2:如果想按照字段名不同,但是值相同的字段进行筛选,怎么办?

解决1:使用using关键字   

注意: 指明的字段必须是两表的同名同值字段

格式: select 内容  from  表名1 inner join 表名2 using(字段名1,字段名2...)

select * from emp inner join dept using(deptno);

这个例子不是太恰当,因为这两个表只有deptno是相同的,  如果这两个表有两列是字段相同且值相同,而只想用一列进行连接筛选时使用using即可。 

解决2:使用on关键字进行自定义连接条件筛选(等值筛选,不等值筛选)

注意:普通条件筛选使用where进行筛选,不要使用on   好处:使得SQL语句的阅读性变强

 格式: select 内容  from  表名1 inner join 表名2 on 连接条件 where 普通筛选条件

select * from emp inner join dept on emp.deptno=dept.deptno where sal>2000;

外连接

左外连接    select 内容 from 表名 left outer join 表名 on 连接条件

--查询员工姓名,工作,薪资,部门名称以及没有部门的员工信息
select e.ename,e.job,e.sal,d.dname from emp e left outer join dept d on e.deptno=d.deptno;

右外连接    select 内容 from 表名 right outer join 表名 on 连接条件

--查询员工姓名,工作,薪资,部门名称以及没有员工信息的部门
select e.ename,e.job,e.sal,d.dname from emp e right outer join dept d on e.deptno=d.deptno;

全外连接    select 内容 from 表名 full outer join 表名 on 连接条件

左右两个没有值的数据都会显示出来

--查询员工姓名,工作,薪资,部门名称以及没有员工信息的部门或没有部门的员工信息
select e.ename,e.job,e.sal,d.dname from emp e full outer join dept d on e.deptno=d.deptno;

自连接

select 内容 from 表名1 inner join 表名2 on 连接条

--查询员工姓名,工作,工资及上级领导姓名
select e1.ename,e1.job,e1.sal, e2.ename from emp e1 inner join emp e2 on e1.mgr=e2.empno;

3.总结

通过三表联合查询对比SQL92和SQL99

SQL92实现:

--查询员工信息及部门名称以及所在城市名称并且要求员工工资大于2000或者有奖金并且按工资排序
select e.*,d.dname,c.cname 
from emp e,dept d,city c 
where (e.deptno=d.deptno and d.loc=c.cid and e.sal>2000) or (e.deptno=d.deptno and d.loc=c.cid and e.comm is not null)
order by e.sal;

特点:易于书写,难于阅读

缺点:92的SQL语句结构不清晰

用法:

select 内容 from 表名1,表名2...
where 条件(连接条件,普通筛选条件,where子句关键字)
group by 分组字段
having 多行函数筛选
order 排序字段

SQL99实现:

--查询员工信息及部门名称以及所在城市名称并且要求员工工资大于2000或者有奖金并且按工资排序
select e.*,d.dname,c.cname from emp e 
inner join dept d 
on e.deptno=d.deptno
inner join city c 
on d.loc=c.cid 
where e.sal>2000 or e.comm is not null
order by e.sal;

特点:难于书写,易于阅读

用法:

select 内容 from 表名1 
inner join 表名2 
on 连接条件
inner join 表名3 
on 连接条件
where 普通筛选条件
group by 分组
having 多行函数筛选
order by 排序