oracle高级查询

作者: xiaoxiao苏 | 来源:发表于2016-12-24 09:34 被阅读104次

    幕课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高级查询

        本文链接:https://www.haomeiwen.com/subject/whylvttx.html