oracle高级查询
==================================================
分组查询,多表查询,子查询。
格式:
SELECT column1[,column2…]
FROM table_name
WHERE conditions
GROUP BY …
HAVIND conditions
ORDER BY …
以下所有例子,都是在oracle安装时的默认数据库中操作的,都可以运行成功。
分组函数:作用于一组数据,并对一组数据返回一个值。
AVG:平均值,SUM:最大值,MIN:最大值,MAX:最小值,COUNT:计算,WM_CONCAT:行转列
select avg(sal),sum(sal) from emp;
select max(sal),min(sal) from emp;
select count(empno) from emp;
select count(distinct depno) from emp;
set linesize 200
col 部门中员工的编号 for a60
select deptno 部门号,wm_concat(ename) 部门中员工的编号 from emp group by deptno;
select sum(comm)|count(*) avg_comm,sum(comm)/count(comm) avg_comm,avg(comm) avg_comm from emp;
分组函数会自动过滤掉空值,所以执行结果不一样。oracle中使用NVL函数使分组函数无法忽略空值。
NVL(value,def_value):当value为空时,返回def_value。
select count(comm),count(nvl(comm,0)) from emp;
select a,b,c,组函数(X) from table group by a,b,c;
先按a进行分组,a相同的看b,b相同的看c,如果都相同,则为一组。
注意:在select列表中所有未包含在组函数中的列都应该包含在GROUP BY子句中;包含在GROUP BY子句中的列不必包含在SELECT列表中。
显示部门的平均工资:部门号,平均工资
select deptno,avg(sal) from emp group by deptno;
按部门不同的职位,统计员工的工资总额
select deptno,job,sum(sal) from emp group by deptno,job order by deptno;
非法使用组函数:
select deptno,count(ename) from emp;
错误:所有包含于select列表中,而未包含于组函数中的列都必须包含在GROUP BY子句中。
HAVING group_condition
平均工资大于2000的部门:
select deptno,sum(sal) from emp group by deptno having sum(sal)>2000;
同样都是过滤数据,where和having的区别:不能在where子句中使用组函数,可以在having子句中使用组函数。
select deptno,avg(sal) from emp group by deptno having deptno=10;
select deptno,avg(sal) from emp where deptno=10 group by deptno;
如果过滤条件中没有分组函数时,where与having通用,那么从sql优化的角度来讲,where的效率更高,因为having是先分组再过滤,而where是先过滤再分组,所以,同等条件下,尽量使用where。
select deptno,avg(sal) from emp group by deptno order by 2 –select表达式的数目
–a命令 append,追加到上一个命令后面。注意必须添加两个及两个以上的空格
a desc
求出平均工资的最大值
select max(avg(sal)) from emp group by deptno;
group by rollup(a,b)–先对a,b分组;在对a分组;最后不分组
select deptno,job,sum(sal) from emp group by rollup(deptno,job);
= select deptno,job,sum(sal) from emp group by deptno,job+select deptno,job,sum(sal) from emp group by deptno+select deptno,job,sum(sal) from emp
break on deptno skip 2–相同的部门号只显示一次,不同的部门号空两行
ttitle col 15 ‘我的报表’ col 35 sql.pno
col deptno heading 部门号
col job heading 职位
col sum(sal) heading 工资总额
break on deptno skip 1
将设置保存为.sql格式的文件,把它保存到一个目录下,然后我们可以在sqlplus中把这个文件用get语句加上路径读取进来,然后我们要执行的话就输入一个@然后加上路径,这样格式就设置好了,我们就可以执行sql语句了,执行sql语句后就会显示成我们设置的格式。
多个表连接进行查询,数学理论——笛卡尔积。
连接条件是‘=’号
select e.empno,e.ename,e.sal,d.dname
from emp e,dept d
where e.deptno=d.deptno–等号连接,等值连接
连接条件不是‘=’号
select e.empno,e.ename,s.grade
from emp e,salgrade s
where e.sal betweem s.losal and s.hisal–between and 小值在前,大值在后
通过外连接,把对于连接条件不成立的记录,仍然包含在最好的结果中,分为左外连接和右外连接。左外连接:当条件不成立的时候,等号左边的表仍然被包含。右外连接:当条件不成立的时候,等号右边的表仍然被包含。
特别注意左外连接和右外连接的写法,位置与名字相反,符号用‘(+)’表示。
左外连接where e.deptno=d.deptno(+);
右外连接where e.deptno(+)=d.deptno;
按部门统计员工人数
select d.deptno 部门号,d.dname 部门名称,count(e.empno) 人数
from emp e,dept d
where e.deptno(+)=d.deptno
group by d.deptno,d.name
通过表的别名,将一张表视为多张表
查询员工姓名和员工的老板姓名
select e.ename 员工姓名,b.ename 员工老板
from emp e,emp b
where e.ename = b.ename
问题:不适合操作大表,原因是自连接至少有两张表参与,并进行笛卡尔全集,连接之后的记录数就是单张表记录数的平方(笛卡尔积行数是两张表行数的乘积)————解决办法:层次查询。
层次查询:可以替代自连接,本质是一个单表查询。
select level,e.empno,e.ename,e.sal,e.mgr–leval伪列
from emp e
connect by prior empno=mgr
start with mgr is null–只有根节点才可以这么表示
order by 1;
层次查询是单表查询,不产生笛卡尔积,但是得到的结果不够直观。
子查询的十个要点:
将子查询语句用“()”括起来。
子查询应该有缩进,方便阅读。
select后只能接单行子查询。
将子查询的结果作为一个表。
select * from (select empno,ename,sal from emp);
select * from (select empno,ename,sal,sal*12 annsal from emp);
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’;–多表查询
理论上讲,推荐用多表查询,因为只访问一次数据库。但是实际上多表查询会产生笛卡尔积。
rownum:oracle中的一个伪列,表示行号。
注意:行号永远按照默认的顺序生成;行号只能使用<,<=,不能使用>,>=.
找到员工表中工资最高的前三名:
select *
from (select * from emp order by sal desc ) where rownum<=3;
相关子查询:外表起别名传递给子查询。
查找员工表中薪水大于本部门平均薪水的员工
select e.empno,e.ename,e.sal,(select avg(sal) from emp where deptno=e.deptno) avgsal
from emp e
where e.sal > (select avg(sal)
from emp
where deptno=e.deptno);
单行子查询操作符:=,<,>,<=,>=,<>
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);
查找部门为sales或者accounting的员工信息:
select *
from emp
where deptno IN (select deptno from dept where dname=’SALES’ or dname=’ACCOUNTING’);
查找工资比30号部门任意一个员工工资都高的员工信息
select *
from emp
where sal > any(select sal from emp where deptno=30);
查找工资比30号部门所有员工工资都高的员工信息
select *
from emp
where sal > all(select sal from emp where deptno=30);
a not in(10,20,null)相当于a!=10 and a!=20 and a!=null,然而a!=null永远为假,
所以要排除空值,判断是否是null值,只能用is or is not而不能用= 或者!=。
查询不是老板的员工:
select *
from emp
where empno not in (select mgr from emp where mgr is not null);
每页显示四条记录,显示第二页的员工,按照月薪降序排序
select 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
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
explain plan for sql–生成执行计划
select * from tables(dbms_xplan.display)–查看执行计划,查看查询语句耗时的cpu资源
相关子查询比多表查询效率要高。
使用函数的方式:
select count(*) total,sum(decode(to_char(hiredate,’yyyy’),’1980’,1,0)) “1980”,sum(decode(to_char(hiredate,’yyyy’),’1981’,1,0)) “1981”,sum(decode(to_char(hiredate,’yyyy’),’1981’,1,0)) “1981”,sum(decode(to_char(hiredate,’yyyy’),’1982’,1,0)) “1982”,sum(decode(to_char(hiredate,’yyyy’),’1987’,1,0)) “1987” from emp
使用子查询的方式:
select
(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;