多表查询
一、内连接
(一)语法
select table1.column, table2.column
from table1
join table2
on table1.column_name=table2.column_name;
(二)主外键
主外键作为约束条件,用来保证数据的完整性
主键(primer key)
外键(foreign key)
主键一旦被参照就不能随意删除,fk可以为空,但取值一定,根据参照的表的pk
外键用来表示表间关系,一对多
上图中,dept:主键被参照,称为主表,父表
emp:外键参照dept表,称为从表,子表
(三)例子
查找叫Smith的人所在的部门名称
select e.ename, d.dname
from emp e join dept d
on e.deptno=d.deptno
where e.ename='SMITH';
(四)内连接原理
(A)t1表和t2表做内连接,连接条件为on t1.c1=t2.c2,假设t1表做驱动表,t2表做匹配表,记录的匹配过程如下:
1.从t1表中读取第一条记录r1,若它的c1值为1
2.根据该值到t2表中查找匹配的记录,即需要遍历t2表,从t2表中的第一条记录开始,若该记录r1的c2列的值等于1,我们就说这两条记录能够匹配上,那么t1的r1和t2的r1组合起来,作为结果集里的一条记录,否则检测t2表中的下一条记录
3.按照方法2依次将t2表中所有的记录检测一遍,只要匹配就放入结果集中
4.从t1表中读取第二条记录,依次重复步骤2和3,产生最终的结果集
(B)t1表和t2表做内连接,连接条件为on t1.c1=t2.c2,假设t1表做驱动表,t2表做匹配表,记录的匹配有如下三种情况:
1.t1表中的某条记录在t2表中找不到任何一条匹配的记录,那么t1表中的该记录不会出现在结果集中
2.t1表中的某记录在t2表中只有一条匹配的记录,那么t1表中的该记录和t2表中匹配的记录组合成新纪录出现在结果集中
3.t1表中的某条记录在t2表中有多条匹配的记录,那么t1表中的该记录会和t2表中每一条匹配的记录组合成新纪录出现在结果集中
(C)内连接的核心
任何一张表里的记录一定要在另一张表中找到匹配的记录,否则不能出现在结果集中
(D)有两种方式都能得到结果集记录
1.一种t1表做驱动表,t2表做匹配表
2.另一种t2表做驱动表,t1表做匹配表
3.无论哪种方式最终得到的结果集都一样,所不同的是效率
(五)内连接的三种形式
1.等值连接
两张表有描述共同属性的列,常见形式为父表的主键和子表的外键相等
select e.ename, e.sal, d.dname
from emp e join dept d
on e.deptno=d.deptno and e.job='MANAGER';
职位是经理(MANAGER)的员工属于哪些部门
先用条件 e.job='MANAGER'对emp表进行过滤,结果集和dept表内连接
如果把查询结果看成一张表,该查询就是把两张表的数据通过表连接的方式合成一张新表
2.非等值连接
(1)可以用between and这样的非等值运算符将两张表中的列写成一个表达式
(2)所谓表之间的关系,实际指表中的行(记录)之间的关系,该关系通过将表中的列写成表达式来体现
select e.ename, e.sal, s.grade
from emp e join salgrade s
on e.sal between s.losal and s.hisal;
列出员工的名字,工资和等级
3.自连接
(1)同一张表的列之中有关系实际反应的是同一张表的行(记录)之间有关系
(2)通过给表起别名将同一张表的列之间的关系转换成不同表的列之间的关系
select worker.ename, manager.ename
from emp worker join emp manager
on worker.mgr=manager.empno;
二、外连接
(一)语法
select table1.column, table2.column
from table1
left/right/full outer join table2
on table1.column_name=table2.column_name;
(二)外连接的原理
t1表和t2表做外连接,连接条件为from t1 left outer join t2 on t1.c1=t2.c2;
t1表必须做驱动表,t2表必须做匹配表
(A)记录的匹配过程如下:
1.从t1表中读取第一条记录r1,若它的c1值为1
2.根据该值到t2表中查找匹配的记录,即需遍历t2表,从t2表中的第一条记录开始,若该记录(r1)的c2列的值等于1,则这两条记录匹配,那么t1的r1和t2的r2组合起来,作为结果集里的一条记录,否则检测t2表中的下一条记录
3.按照方法2依次将t2表中所有的记录检测一遍,只要匹配就放入结果集中,若扫描完后,t1的r1记录在t2表中找不到任何匹配的记录,t2表中模拟一条null记录与t1表中r1组合起来,放入结果集中
4.从t1表中读取第二条记录,依次重复步骤2和3,产生最终的结果集
(B)匹配的情况
1.外连接的结果集=内连接的结果集+t1表中匹配不上的记录和一条null记录的组合
2.外连接的核心可以将驱动表中匹配不上的记录找回来,即一个都不能少
t1 left outer join t2=t2 right outer join t1
t1 right outer join t2=t2 left outer join t1
t1 full outer join t2=t2 full outer join t1
from t1 right outer join t2 on t1.c1=t2.c2
外连接的结果集=内连接的结果集+t2表中匹配不上的记录和一条null记录的组合
from t1 full outer join t2 on t1.c1=t2.c2
外连接的结果集=内连接的结果集+t2表中匹配不上的记录和一条null记录的组合+t1表中匹配不上的记录和一条null记录的组合
(三)例子
select worker.ename, manager.ename
from emp worker left outer join emp manager
on worker.mgr=manager.empno;
列出所有职员,不管有没有经理
select manager.ename
from emp worker
right outer join emp manager
on worker.mgr=manager.empno
where worker.empno is null;
哪些员工无下属(不是领导)
外连接+匹配表pk is null表示否定问题,不是,不包括,等等
select d.dname
from emp e right outer join dept d
on e.deptno=d.deptno
and e.ename='SMITH'
where e.empno is null;
哪些部门没有名字为SMITH的员工
该语句的执行顺序为对emp表先用e.ename='SMITH'进行过滤,再将结果集和dept表做外连接,生成结果集后,再用where条件对该结果进行过滤,产生最终的结果,这里的结果集如下:
结果集=有SMITH的部门(内连接产生的结果集)+没有SMITH的部门(驱动表中匹配不到的记录和null值的结果集)
三、组函数
max/min/avg/sum/count
select avg(sal) from emp;
select sum(sal) from emp;
select max(sal) from emp;
select min(sal) from emp;
select avg(nvl(comm,0)) from emp;
select count(distinct deptno) from emp;
按照部门分组,计算每个部门的薪水总和:
select deptno, sum(sal)
from emp
group by deptno;
按照职位分组,计算每个职位的平均薪水:
select job,avg(sal)
from emp
group by job;
在select后面,所有的非组函数的列必须出现在group by后面
出现在group by后面的列不一定出现在select后面,但是信息不完整
select avg(sal)
from emp
group by job;
结论:select后面的非组函数的列和group by后面的列明保持一致
获得每个部门每个职位的平均薪水
select deptno, job, avg(sal)
from emp
group by deptno,job
order by deptno,job;