oracle高级查询

幕课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;

你可能感兴趣的:(oracle高级查询)