幕课oracle学习笔记
--!!!scott用户
--一.分组查询
--1.常用的分组函数:AVG(平均数),SUM,MIN,MAX,COUNT,WM_CONCAT(行转列)
select avg(sal),sum(sal) from emp;--工资的平均值,工资的总和
select max(sal),min(sal) from emp;--工资的最大值,最小值
select count(*) from emp;--员工的总数
select count(distinct deptno) from emp;--根据部门号取重查询
select deptno 部门号,wm_concat(ename) 部门中的员工 from emp group by deptno;--行转列,查出各个部门的人员名字
--分组函数会自动过滤空值,使用NVL函数使分组函数无法忽略空值
select avg(comm) from emp;--平均奖金为550
select avg(nvl (comm,0)) from emp;--平均奖金为157.14
--2.分组数据:
--(1)GROUP BY子句:select a,b,c,组函数(x) from table_name group by a,b,c;在select列表中所有未包含在组函数中的列都应该包含在group by子句中
select deptno,avg(sal) from emp group by deptno;
--多个列分组
select deptno,job,sum(sal) from emp group by deptno,job;--求出每个部门各个职位的工资综合
--(2)HAVING子句:过滤分组数据
select deptno,avg(sal) from emp group by deptno having avg(sal)>2000;--求出平局工资大于2000的部门
--where子句中不能使用分组函数,可以在having几组中使用;
--从sql优化的角度,没有组函数.分组函数时where和having通用,尽量使用where(效率高)
select deptno,avg(sal) from emp group by deptno having deptno=10;--10号部门的平均工资
select deptno,avg(sal) from emp where deptno=10 group by deptno ;--10号部门的平均工资
--(3)order by子句:默认升序,降序+desc
select deptno,avg(sal) 平均工资 from emp group by deptno order by 平均工资;--各部门平均工资并升序排列
select deptno,avg(sal) 平均工资 from emp group by deptno order by 2;--根据select语句的第二列排序
select deptno,avg(sal) 平均工资 from emp group by deptno order by 2 desc;
--(4)分组函数的嵌套
select max(avg(sal)) from emp group by deptno;--平均工资最高的部门的平均工资
--(5)group by语句的增强:rollup();主要应用于报表
select deptno,job,sum(sal) from emp group by deptno,job;
select deptno,sum(sal) from emp group by deptno;
select sum(sal) from emp;--以上三句查询与下面的增强查询结果一致
select deptno,job,sum(sal) from emp group by rollup(deptno,job);
--二.多表查询
--笛卡尔积:多张表的列数相加,行数相乘所得的新表。;为了避免笛卡尔积,可以在where加入有效的连接条件
--四种连接(等值连接,不等值连接,外连接,自连接);
(1)等值连接
select e.empno,e.ename,e.sal,d.dname from emp e,dept d where e.deptno=d.deptno;
(2)不等值连接
select e.empno,e.ename,e.sal,s.grade from emp e,salgrade s where e.sal between s.losal and s.hisal;
或select e.empno,e.ename,e.sal,s.grade from emp e,salgrade s where e.sal>=s.losal and e.sal<=s.hisal;
(3)外连接:把对于连接条件不成立的记录,仍然包含在结果中;
--下列语句查询丢失了deptno=40的部门,因为40部门人数为0
select d.deptno 部门号,d.dname 部门名称,count(e.empno) 部门人数 from emp e,dept d where e.deptno=d.deptno group by d.deptno,d.dname;
--左外连接:连接条件不成立时,等号左边的仍然被包含;在连接条件左边加 : (+)
select d.deptno 部门号,d.dname 部门名称,count(e.empno) 部门人数 from emp e,dept d where e.deptno(+)=d.deptno group by d.deptno,d.dname;
--右外连接:连接条件不成立时,等号右边的仍然被包含;在连接条件右边加 : (+)
(4)自连接(不适合操作大表):通过别名,将同一张表视为多张表
select e.ename,b.ename from emp e,emp b where e.mgr=b.empno;--获得员工的名字和他上级的名字
--层次查询(解决自连接操作大表的笛卡尔积问题):某种情况下可以替代自连接,本质上是一个单表查询;结果没有自连接直观
select level,empno,ename,sal,mgr from emp connect by prior empno=mgr start with mgr is null order by 1;
ps:connect by 上一层的员工号=老板号;start with 老板号为空,即子节点开始;level:伪列,代表树形结构等级;order by 1 表示按level第一层开始排序
--三.子查询(select语句的嵌套)
--(1)可以使用子查询的位置:where,select,having,from
select ename from emp where sal>(select sal from emp where ename='SCOTT');--工资比scott高的员工
select empno,ename,sal,(select job from emp where empno=7839) from emp;--所有员工的职位都是7839的职位
select deptno,avg(sal) from emp group by deptno having avg(sal)>(select max(sal) from emp where deptno=30);--部门平均工资大于30部门工资最大值的部门
select * from (select empno,ename,sal from emp);
--(2)不可以使用子查询的位置:group by
***错误提示:ORA-22818:这里不允许出现子查询表达式**
select avg(sal) from emp group by(select deptno from emp);
--(3)*from 后面的子查询
*******:在已知条件的基础上得到更多的已知条件
select * from (select empno,ename,sal from emp);
select * from (select empno,ename,sal 月薪,sal*12 年薪 from emp);
--(4)主查询,子查询可以不是同一张表,只要子查询的结果主查询可以使用就可以!
select * from emp where deptno=(select deptno from dept where dname='SALES');
--也可以使用多表查询实现上述查询
select e.* from emp e,dept d where e.deptno=d.deptno and d.dname='SALES';
--理论上尽量使用多表查询,只有一个from,只访问一次数据库.
--(5)一般不在子查询中使用排序,但在TOP-N分析问题中,必须对子查询排序
--TOP-N问题:例如薪水前三的员工
--rownum 行号,oracle提供的伪列;永远按照默认的顺序生成(无任何条件的查询表时的顺序),只能使用<,<=;不能使用>,>=(分页查询时使用此特性)
--解决上述伪列默认顺序导致查询永远是前三个员工,而非工资前三的员工的问题
--不使用原表,而使用倒序排列后的新表作为查询表
select rownum,empno,ename,sal from (select * from emp order by sal desc) where rownum<=3;
--(6)一般先执行子查询,再执行主查询;但相关子查询例外
--查询员工标中薪水大于本部门平均水平的员工(相关子查询:主查询的中的值作为参数传给子查询,主查询必须起别名)
select empno,ename,sal,(select avg(sal) from emp where deptno=e.deptno) avgsal from emp e where sal>(select avg(sal) from emp where deptno=e.deptno);
--(7)单行子查询(返回单行记录)只能使用单行操作符(=,>,>=,<,<=,<>)
--职位与7566员工一样,薪水大于7782员工的薪水
select * from emp where job=(select job from emp where empno=7566) and sal >(select sal from emp where empno=7782);
--查询薪水最低的员工信息
select * from emp where sal=(select min(sal) from emp);
--查询最低工资大于20号部门最低工资的部门号和部门的最低工资
select deptno,min(sal) from emp group by deptno having min(sal)>(select min(sal) from emp where deptno=20);
--多行子查询(返回多行记录)只能使用多行操作符(in:等于列表中的任何一个,any:和子查询返回的任意一个值比较,all:和子查询返回的所有值比较)
--in:查询部门名称是sales和accounting的员工信息
select * from emp where deptno in (select deptno from dept where dname='SALES' or dname='ACCOUNTING');--子查询
select e.* from emp e ,dept d where e.deptno=d.deptno and (d.dname='SALES' or d.dname='ACCOUNTING');--多表联查(加括号,必须先执行or,再执行and)
--any:查询工资比30号部门任意一个员工高的员工信息
select * from emp where sal>any(select sal from emp where deptno=30);
select * from emp where sal>(select min(sal) from emp where deptno=30);
--all:查询工资比30部门所有员工高的员工信息
select * from emp where sal>all(select sal from emp where deptno=30);
select * from emp where sal>(select max(sal) from emp where deptno=30);
--(8)子查询中的null值问题(主要是多行子查询中)
--查询不是老板的员工
select * from emp where empno not in(select mgr from emp where mgr is not null);--(子查询中不能有空值,否则就查不到任何数据)
ps: a not in (10,20,null)就等同于 a!=10 and a!=20 and a!=null;因为a!=null永远为假,所有条件就永远为假,就查不出任何结果
--四.示例
(1)分页查询显示员工信息:显示员工号,姓名,月薪(每页显示四条;显示第二页的员工;按照月薪降序排列)
--rownum伪列,始终从1开始,无法使用大于(>)和大于等于(>=)
select rownum,r,empno,ename,sal from
(select rownum r,empno,ename,sal from(select rownum,empno,ename,sal from emp order by sal desc) e1 where rownum<=8) e2
where r>=5;
(2)员工表中薪水大于本部门平均薪水的员工
select empno,ename,sal,(select avg(sal) from emp where deptno=e.deptno) avgsal
from emp e
where sal>(select avg(sal) from emp where deptno=e.deptno);--相关子查询--相比多表查询更节省cpu资源
--------------------------------------------
select e.empno,e.ename,e.sal,d.avgsal
from emp e,(select deptno,avg(sal) avgsal from emp group by deptno) d
where e.deptno=d.deptno and e.sal>d.avgsal;--多表联查
(3)按部门统计员工,分别查出总人数,及1980,1981,1982,1987年入职的员工
select count(*) total,--使用函数的方式
sum(decode(to_char(hiredate,'YYYY'),'1980',1,0)) "1980",--to_char转换出入职日期中的年
sum(decode(to_char(hiredate,'YYYY'),'1981',1,0)) "1981",--并与四位年份比较
sum(decode(to_char(hiredate,'YYYY'),'1982',1,0)) "1982",--相同则返回1,不同返回0
sum(decode(to_char(hiredate,'YYYY'),'1987',1,0)) "1987"--sum算出1和0的总和,即为该年份入职的人数
from emp;
-------------------------------------------------
select --使用子查询+伪表dual的方式
(select count(*) from emp ) total,
(select count(*) from emp where to_char(hiredate,'yyyy')='1980') "1980",
(select count(*) from emp where to_char(hiredate,'yyyy')='1981') "1981",
(select count(*) from emp where to_char(hiredate,'yyyy')='1982') "1982",
(select count(*) from emp where to_char(hiredate,'yyyy')='1987') "1987"
from dual;