5.oracle_高级查询

分组查询

常用的分组函数:AVG、sum、min、max、count、wm_concat

①select count(distinct deptno) from emp;

②select deptno,wm_concat(ename) from emp group by deptno;

 

小技巧:set linesize 200;--设置显示宽度

 

算平均工资有3种方式

一、sun(sal)/count(*)

二、sun(sal)/count(sal)

三、avg(sal)

注意:nvl函数使分组函数无法忽略空值,将空值换为0。

 

分组数据 group by子句的使用

语法

Select column,group_function(column)

From table

[where     condition]

[group by   group_by_expression]

[order by   column];

可以使用group by子句将表中的数据分成若干组。

 

示例:求每个部门的平均工资,要求显示:部门号,部门的平均工资。

Select deptno,avg(sal) From emp Group by deptno;

抽象:Select a,b,c,a组函数(X) From table Group by a,b,c;

结论:①在select列表中所有未包含在组函数中的列都应该包含在Group by子句中。

           ②包含在Group by 子句中的列不必包含在select列表中

示例:求每个部门的平均工资,要求显示部门:部门的平均工资。

Select avg(sal) from emp group by deptno;

 

多个列分组

示例:按部门、不同职位,统计员工的工资总额

Select deptno,job,sum(sal) from emp group by deptno,job order by deptno;

 

非法使用组函数

所用包含于select列表中,而未包含于组函数中的列都必须包含于group by子句中。

Select deptno,count(ename) from emp;

 

Having子句的使用:过滤分组数据

语法:

Select column,group_function

From table

[where condition]

[group by graoup_by_expression]

[having group_condition]

[order by column];

示例:

求平均工资大于2000的部门,要求显示:部门号,平均工资

Select avg(sal) from emp group by deptno having avg(sal)>2000;

 

Where 与having的区别

①不能在where子句中使用组函数。

②可以在HAVING子句中使用组函数。

错误示例:

Select deptno,avg(sal)

From emp

Where avg(sal)>2000

Group by deptno;

 

Where与having可以通用的情况

示例:查询10号部门的平均工资

Select deptno,avg(sal)

From emp

Group by deptno

Having deptno=10;

 

Select deptno,avg(sal)

From emp

Where deptno

Group by deptno;

尽量使用Where 效率高

 

在分组查询中使用order函数

示例:求每个部门的平均工资,要求显示部门号。部门的平均工资,并且按照工资升序排列。

可以按照:列、列名、表达式、序号进行排序。

Select deptno,avg(sal) 平均工资  --可以用别名

From emp

Group by deptno

Order by avg(sal)               --可以用别名、可以用列序号

--a命令 append 表示在上一条sql语句后面加上...       a  desc       /

分组函数的嵌套

示例:求部门平均工资的最大值

Select max(avg(sal))

From Emp

Group by deptno

 

Group by 语句的增强

 

分析:

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

语法:

Group by rollup(a,b)

等价于:

Group by a,b

+

Group by a

+

Group by null

 

Break on deptno skip 2  相同部门号的数字只显示一次

 

Set pagesize 30 设置显示30行

 

 

SQL*Plus的报表功能

报表包括:标题、页码、别名等。

SQL*Plus的报表功能

Ttitle col 15 ‘我的报表’ col 35 sql.pno

Col deptno heading 部门号

Col job heading职位

Col sum(sal) heading 工资总额

Break on deptno skip 1   

Get d:\temp\report.sql        //读取文件,设置格式

 

多表查询(笛卡尔集)

为了避免笛卡尔集,可以在where加入有效的连接条件,在实际运行环境下,应避免使用笛卡尔全集。

 

等值连接

示例:查询员工信息,要求显示:员工号,姓名,月薪,部门名称

Select e.empno,e.ename,e.sal,d.dname from emp e,dept d where e.deptno d.deptno;

 

不等值连接

示例:查询员工信息,要求显示:员工号,姓名,月薪,薪水的级别

Select * from salgrade;--查询工资级别表

Select e.empno,e.ename,e.sal,s.grade

From emp e,salgrade s

Where e.sal beteen s.losal and s.hisal;

 

外连接

核心:通过外连接,把对于连接条件不成立的记录,仍然包含在最后的结果中。

左外链接:当连接条件不成立的时候,等号左边的表仍然被包含

右外链接:当连接条件不成立的时候,等号右边的表仍然被包含

示例:按部门统计员工人数,要求显示:部门号,部门名称,人数

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 e.ename 员工姓名,b.ename 老板姓名

From emp e,emp b

Where e.mgr=b.empno;

 

自连接存在的问题

不适合操作大表

解决办法:层次查询

         某些情况下,可以替代自连接

         本质上,是一个单表查询、

   

Select level,empno,ename,sal,mgr  --level伪列

From emp

Connect by prior empno=mgr -- Connect by连接  条件:上一层的员工号=这一层的老板号

Start with empno=7839; --从empno遍历这个树,等价Start with mgr is null;mgr上级部门号

Order by 1;

子查询

子查询概述

         单行子查询:返回1条记录

多行子查询:返回多条记录

子查询的使用

语法:

Select select_list

From table

Where expr operator

(

Select select_list

From table

);

示例:查询工资比scott高的员工信息

Select *from emp where sal>( Select sal from emp where ename=‘SCOTT’);

 

子查询注意的10个问题:

l  子查询语法中的小括号

l  子查询的书写风格

l  可以使用子查询的位置:where,select,having,from

l  不可以使用的子查询的位置:group by后面不能使用子查询

l  强调:from后面的子查询

l  主查询和子查询可以不是同一张表

 

多表查询比子查询好

 

l  一般不在子查询中,使用排序;但在Top-N分析问题中,必须对子查询排序

--rownum行号 伪列。行号永远按照默认的顺序生存,不随排序而变化,行号只能使用<,<=;不能使用>,>=。

 

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

示例:找到员工表中薪水大于本部门平均薪水的员工

Select empno,ename,sal,(select vag(sal) from emp where deptno=e.deptno) avgsal

From emp e

Where sal>(select avg(sal)from emp where deptno=e.deptno);

 

l  单行子查询只能使用单行操作符;多行子查询只能使用多行操作符

 

 

示例:查询员工信息,要求:职位与7566员工一样,薪水大于7782员工的薪水

 

 

Select * from emp where deptno in

(select deptno from dept where dname=’sales’ or dname=’accounting’)

也可以用多表查询。

 

Select * from emp where sal>any (select sal from emp where deptno=30);

Select * from emp where sal>all (select sal from emp where deptno=30);

 

l  注意:子查询中是null值问题

 

 

主要问题是注意子查询中的结果不能为空

 

多表查询比子查询好

子查询的类型

 

综合示例

案例1

分页查询显示员工信息:显示员工号、姓名、月薪

-每页显示4条记录

显示第二页的员工

-按照月薪降序排列

提示:rownum

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;

 

案例二

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

 

 

Explain plan for  --得到下面语句的执行计划

Select empno,ename,sal,(select avg(sal) from emp where deptnoe.deptno)avgsal

From emp e

Where sal>(select avg(sal) from emp where deptno=e.deptno);

 

Select * from table (dbms_xplan.display);--查看刚刚的执行计划

以上代码和下面的查询结果一样

Select e.empno,e.ename,e.sal,d.avgsal

From emp e,(select deptno,avg(sal) avgsal from emp group by deptno)

Where e.deptno=d.deptno and e.sal>d.avgsal;

上部分代码占用资源少。

 

案例三

按部门统计员工人数,按照如下格式输出:

 

 

注意:员工的入职年份已知

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’),’1982’,1,0))”1982”,

         Sum(decode(to_char(hiredate,’YYYY’),’1987’,1,0))”1987”,

From emp;

Host cls 清除文字

用子查询方式

select

(select count(*)from emp)Total,

(select count(*)from emp where to_char(hiredate,’yyyy’)=’1980’)

(select count(*)from emp where to_char(hiredate,’yyyy’)=’1981’)

(select count(*)from emp where to_char(hiredate,’yyyy’)=’1982’)

(select count(*)from emp where to_char(hiredate,’yyyy’)=’1987’)

From dual;

 

案例四

 

 

select cstu.ci_id, wm_concat(stu.stu_name) stu_name

from (select c.ci_id, stu.stu_name

from PM_CI c, PM_STU stu

where instr(c.stu_ids, stu.stu_id) != 0) cstu

group by cstu.ci_id

在Oracle中 可以使用instr函数对某个字符串进行判断,判断其是否含有指定的字符。

posted @ 2016-07-25 10:24  周银胜  阅读(93)  评论(0)    收藏  举报