一、学习目标
内连接
外连接
子查询
exists运算符
分页(重点,难点)
课堂练习
集合运算符
递归查询
二、内连接
-- 内连接
-- 举例:查询员工表和部门表的记录
-- 笛卡尔积:员工表中的任意一条记录要和部门表中的每一条记录相关联
select * from emp ,dept ;
-- 避免笛卡尔积: 设置条件(从表中外键=主表主键)
select * from emp ,dept where emp.deptno = dept.deptno;
select * from emp e , dept d where e.deptno = d.deptno;
-- 举例:查询员工的上级领导
select * from emp e, emp m where e.mgr = m.empno;
-- 举例:在上面的基础上:查询员工的部门名称
select e.empno ,e.ename,d.dname ,'||',m.empno ,m.ename
from emp e, emp m ,dept d
where e.mgr = m.empno and e.deptno = d.deptno;
-- 举例:在上面的基础上:查询领导的部门名称
select e.empno ,e.ename,d.dname ,'||',m.empno ,m.ename,d2.dname
from emp e, emp m ,dept d ,dept d2
where e.mgr = m.empno and e.deptno = d.deptno
and m.deptno = d2.deptno;
-- 举例:在上面的基础上,查询员工和领导的工资等级
select e.empno ,e.ename,d.dname ,s1.grade,'||',m.empno ,m.ename,d2.dname ,s2.grade
from emp e, emp m ,dept d ,dept d2, salgrade s1 ,salgrade s2
where e.mgr = m.empno and e.deptno = d.deptno
and m.deptno = d2.deptno
and e.sal between s1.losal and s1.hisal
and m.sal between s2.losal and s2.hisal;
-- 条件表达式
-- case when
/*
case 表达式
when 值 then 返回值
when 值 then 返回值
when 值 then 返回值
when 值 then 返回值
....
else 返回值
end
*/
-- 举例:当输入1时,返回一 ,输入2时,返回二....
select
case 3
when 1 then '一'
when 2 then '二'
else '其他'
end
from dual;
select e.empno ,e.ename,d.dname ,
case s1.grade
when 1 then '一级'
when 2 then '二级'
when 3 then '三级'
when 4 then '四级'
else '其他'
end 员工工资等级
,'||',m.empno ,m.ename,d2.dname ,s2.grade
from emp e, emp m ,dept d ,dept d2, salgrade s1 ,salgrade s2
where e.mgr = m.empno and e.deptno = d.deptno
and m.deptno = d2.deptno
and e.sal between s1.losal and s1.hisal
and m.sal between s2.losal and s2.hisal;
-- decode
-- decode(表达式 ,key,value ,key,value,...., elsevalue)
select e.empno ,e.ename,d.dname ,
case s1.grade
when 1 then '一级'
when 2 then '二级'
when 3 then '三级'
when 4 then '四级'
else '其他'
end 员工工资等级
,'||',m.empno ,m.ename,d2.dname ,
decode(s2.grade ,4,'四级',5,'五级','其他')领导的工资等级
from emp e, emp m ,dept d ,dept d2, salgrade s1 ,salgrade s2
where e.mgr = m.empno and e.deptno = d.deptno
and m.deptno = d2.deptno
and e.sal between s1.losal and s1.hisal
and m.sal between s2.losal and s2.hisal;
三、外连接
-- 外连接:能显示基准表中所有的记录
-- 举例:查询员工的上级领导
--左外连接:select * from 左表 left join 右表 on 条件
select e.empno ,e.ename,m.empno ,m.ename
from emp e left join emp m
on e.mgr = m.empno;
--右外连接:select * from 左表 right join 右表 on 条件
select e.empno ,e.ename,m.empno ,m.ename
from emp m right join emp e
on e.mgr = m.empno;
--全外连接(了解):select * from 左表 full join 右表 on 条件
select e.empno ,e.ename,m.empno ,m.ename
from emp m full join emp e
on e.mgr = m.empno;
--特殊外连接:由内连接改造来的
-- (+) : 显示对方表中的所有记录
select e.empno ,e.ename,m.empno ,m.ename
from emp e , emp m
where e.mgr = m.empno(+);
四、子查询
子查询:在一条sql语句中包含另一条sql查询语句
-- 外查询 内查询
-- 举例:查询与7876工作一样的员工
select * from emp where job = (select job from emp where empno = 7876);
-- 举例:查询存在员工的部门信息
-- 先查询存在员工部门编号
select distinct deptno from emp ;
-- 查询部门的信息: in(set): set 必须是一个固定的集合,或者是一个一列多行的结果集
select * from dept where deptno in (10,20,30);
select * from dept where deptno =any (10,20,30); -- =some
-- 标准的语句
select * from dept where deptno in (select distinct deptno from emp);
-- 查询每个部门的最低工资的员工信息
-- 先查询每个部门的最低工资
select min(sal) minsal,deptno from emp group by deptno;
-- 查询员工信息:如果结果集是多行多列,作为一张表使用,必须取别名
select e.empno ,e.ename ,e.sal ,e.deptno, t.minsal ,t.deptno
from emp e,(select min(sal) minsal,deptno from emp group by deptno) t
where e.deptno = t.deptno and t.minsal = e.sal;
-- 查询与7790工作一样的员工信息
select * from emp where job = (select job from emp where empno = 7790);
-- 子查询小结
-- 返回一个值:可以使用 = != <> <= >=
-- 返回一列多行:使用in ,=any ,=some
-- 返回多行多列:把结果集作为表使用
-- 返回null: 不会报错
五、exists运算符
-- exists 运算符(效率较高):存在 ,只会返回两个值:true ,false
select * from emp where exists (select * from emp where empno = 7788);
select * from emp where 1=1;
select * from emp where exists (select * from emp where empno = 8890);
select * from emp where 1=2;
-- 举例:查询存在员工的部门信息
select * from dept d where exists (select distinct deptno from emp e where d.deptno=e.deptno)
select * from dept where deptno in( select distinct deptno from emp)--效率 没有xists高
六、分页
-- 伪列:
--rowid 行编号: 在添加记录时生成,存储的内存地址
select e.*,rowid from emp e where rowid= 'AAAMfPAAEAAAAAgAAA';
-- rownum : 行号,每加载一条记录生成一个行号,行号是从1 开始,依次递增,每次递增一个
-- 分页
select e.*,rownum from emp e;
-- 举例:查询员工表的前三条记录
select e.*,rownum from emp e where rownum <= 3;
-- 举例:查询员工表的4-6条记录
-- 先生成行号
select e.*,rownum from emp e
-- 把结果集作为表使用,做条件筛选
select t.*
from (select e.*,rownum rn from emp e) t
where t.rn between 4 and 6;
-- 举例: 查询工资最高的前三名
-- 先工资的降序排序
select e.* from emp e order by sal desc;
-- 把结果集作为表使用,再生成行号
select t.*
from (select e.* from emp e order by sal desc) t
where rownum <= 3
-- 举例: 查询工资最高的 4 - 6名
-- 先按照工资的降序排序
select e.* from emp e order by sal desc
-- 作为表示用,生成行号
select t.* ,rownum rn from (select e.* from emp e order by sal desc) t
-- 作为表示用,条件筛选
select m.*
from (select t.* ,rownum rn from (select e.* from emp e order by sal desc) t) m
where m.rn between 4 and 6;
-- 分析函数: row_number() over(排序语句)
select t.*
from (select e.* ,row_number() over(order by sal desc) rn from emp e) t
where t.rn between 4 and 6;
七、课堂练习
-- 查询员工的薪水大于本部门平均薪水的员工
-- 先查询每个部门的平均薪水
select avg(sal) , deptno from emp group by deptno;
-- 条件筛选
select e.empno ,e.ename ,e.sal ,e.deptno , t.avgsal ,t.deptno
from emp e ,(select avg(sal) avgsal , deptno from emp group by deptno) t
where e.deptno = t.deptno and e.sal > t.avgsal;
-- 查询每年入职的员工个数
select count(1),to_char(hiredate ,'yyyy') hireyear from emp group by to_char(hiredate ,'yyyy');
-- 行列转换
select sum(c) "Total",
avg(decode(hireyear ,'1980',c)) "1980",
avg(decode(hireyear ,'1981',c)) "1981",
avg(decode(hireyear ,'1982',c)) "1982",
avg(decode(hireyear ,'1987',c)) "1987"
from (select count(1) c,to_char(hiredate ,'yyyy') hireyear
from emp group by to_char(hiredate ,'yyyy')) t
八、集合运算
-- 交集
select * from emp where deptno = 20
intersect
select * from emp where job = 'CLERK';
select * from emp where deptno = 20 and job = 'CLERK';
-- 并集: union all 不会去除重复的记录
-- union会去除重复的记录 , 会触发索引
select * from emp where deptno = 20
union
select * from emp where job = 'CLERK';
-- 不会触发索引
select * from emp where deptno = 20 or job = 'CLERK';
-- 差集: A B
-- 在A集合中出现的,在B集合中没有出现
select * from emp where deptno = 20
minus
select * from emp where job = 'CLERK';
select * from emp where job = 'CLERK'
minus
select * from emp where deptno = 20;
-- 前提:两个集合:类型,顺序,个数一致即可
select empno ,ename from emp where deptno = 20
union
select deptno ,dname from dept;
九、递归查询
--- 递归查询(单表的递归查询)(了解)
-- 语法:
/*
select * from 表
条件一: 设置起始位置
start with 条件
条件二: 设置关联条件,设置方向
connect by 条件;
*/
-- 查询某员工的领导信息,领导的领导信息,....
select * from emp
start with empno = 7369
connect by prior mgr = empno;
-- 查询某员工的下属员工,下属的下属,....
select * from emp
start with empno = 7839
connect by mgr = prior empno;