您的位置:首页 > 数据库 > Oracle

[oracle学习笔记]之三:高级查询

2015-09-30 14:39 609 查看
oracle高级查询

==================================================

分组查询,多表查询,子查询。

格式:

SELECT column1[,column2…]

FROM table_name

WHERE conditions

GROUP BY …

H***IND conditions

ORDER BY …

以下所有例子,都是在oracle安装时的默认数据库中操作的,都可以运行成功。

分组查询:

分组函数:作用于一组数据,并对一组数据返回一个值。

1、常用的分组函数:***G,SUM,MIN,MAX,COUNT,WM_CONCAT

***G:平均值,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;

2、分组函数和空值:

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;

3、group by子句:

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子句中。

4、过滤分组——having子句

H***ING 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。

5、使用order by子句进行排序

select deptno,avg(sal) from emp group by deptno order by 2 –select表达式的数目

–a命令 append,追加到上一个命令后面。注意必须添加两个及两个以上的空格

a desc

6、嵌套分组函数

求出平均工资的最大值

select max(avg(sal)) from emp group by deptno;

7、group by语句增强–适用于报表

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–相同的部门号只显示一次,不同的部门号空两行

8、SQL/PLUS报表功能

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语句后就会显示成我们设置的格式。

多表查询

多个表连接进行查询,数学理论——笛卡尔积。

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,s.grade

from emp e,salgrade s

where e.sal betweem s.losal and s.hisal–between and 小值在前,大值在后

3、外连接

通过外连接,把对于连接条件不成立的记录,仍然包含在最好的结果中,分为左外连接和右外连接。左外连接:当条件不成立的时候,等号左边的表仍然被包含。右外连接:当条件不成立的时候,等号右边的表仍然被包含。

特别注意左外连接和右外连接的写法,位置与名字相反,符号用‘(+)’表示。

左外连接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

4、自连接

通过表的别名,将一张表视为多张表

查询员工姓名和员工的老板姓名

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;

层次查询是单表查询,不产生笛卡尔积,但是得到的结果不够直观。

子查询

子查询的十个要点:

1、子查询语法的小括号;

将子查询语句用“()”括起来。

2、书写风格;

子查询应该有缩进,方便阅读。

3、在where,select,having,from中使用;

select后只能接单行子查询。

4、不可以在group by中使用;

5、from后面的子查询;

将子查询的结果作为一个表。

select * from (select empno,ename,sal from emp);

select * from (select empno,ename,sal,sal*12 annsal from emp);

6、主查询和子查询可以不是同一张表;

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’;–多表查询

理论上讲,推荐用多表查询,因为只访问一次数据库。但是实际上多表查询会产生笛卡尔积。

7、一般不在子查询中使用排序,但在top-n分区问题中,必须对子查询进行排序;

rownum:oracle中的一个伪列,表示行号。

注意:行号永远按照默认的顺序生成;行号只能使用<,<=,不能使用>,>=.

找到员工表中工资最高的前三名:

select *

from (select * from emp order by sal desc ) where rownum<=3;

8、一般先进行子查询再执行主查询,但相关子查询例外;

相关子查询:外表起别名传递给子查询。

查找员工表中薪水大于本部门平均薪水的员工

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);

9、单行子查询只能使用单行操作符,多行子查询只能使用多行操作符;

单行子查询操作符:=,<,>,<=,>=,<>

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);

多行子查询操作符:IN,ANY,ALL

查找部门为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);

10、注意子查询中null值问题。

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);

高级查询实例

1、分页显示员工信息:显示员工号,姓名,月薪

每页显示四条记录,显示第二页的员工,按照月薪降序排序

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

2、找到员工表中薪水大于本部门平均薪水的员工

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资源

相关子查询比多表查询效率要高。

3、按部门统计员工人数,

使用函数的方式:

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;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: