Oracle 数据库学习笔记03

时间:2021-03-08 08:37:46

Oracle 数据库 ( SQL 高级查询)

1. 子查询

子查询就是一条SQL语句,它是嵌套在其他SQL语句中的,目的是为实际的SQL语句提供数据
子查询可以应用在 DQL, DDL, DML 中

查看比 CLARK 工资高的员工信息

SELECT ename,sal FROM emp
WHERE sal > (SELECT sal FROM emp
WHERE ename = 'CLARK')

查找和CLARK相同部门的其他员工

SELECT ename, deptno FROM emp
WHERE deptno = (SELECT deptno FROM emp
WHERE ename='CLARK')
AND ename<>'CLARK'
  • 子查询在 DDL 中的应用:
    可以根据查询结果集快速创建一张表
CREATE TABLE myemployee AS
SELECT e.empno, e.ename,e.sal,e.job,e.deptno,d.dname,d.loc
FROM emp e JOIN dept d
ON e.deptno= d.deptno;
  • 子查询在 DML 中的应用:
    将CLARK所在部门所有员工的工资加500
UPDATE emp
SET sal= sal+500
WHERE deptno=(SELECT deptno FROM emp WHERE ename='CLARK')

子查询根据查询结果不同,分为:
1. 单行单列子查询: 常用作过滤条件
2. 多行单列子查询: 常用作过滤条件
3. 多行多列子查询: 常当做表看待

  • 多行单列子查询
    查看与职位是 SALESMAN 同部门的其他员工
SELECT ename, job, deptno FROM emp
WHERE deptno IN (SELECT deptno FROM emp
WHERE job='SALESMAN')
AND job <> 'SALESMAN'
  • 多行多列子查询
    查询比本部门平均工资高的员工信息
SELECT e.ename, e.sal, e.deptno
FROM emp e,(SELECT AVG(sal) avg_sal,deptno FROM emp
GROUP BY deptno) s
WHERE e.deptno = s.deptno
AND e.sal > s.avg_sal

练习:

-- 查询4人以上(包含4人)的部门员工的工资是多少
-- 方法1
SELECT e.ename,e.sal,e.deptno
FROM emp e JOIN (SELECT deptno FROM emp
GROUP BY deptno HAVING COUNT(*)>=4 ) d
ON e.deptno=d.deptno;

-- 方法2
SELECT ename, sal,deptno
FROM emp
WHERE deptno IN (SELECT deptno FROM emp
GROUP BY deptno HAVING COUNT(*)>=4 );

-- 方法3
SELECT e.ename,e.sal,e.deptno
FROM emp e,(SELECT COUNT(*) per_num, deptno FROM emp
GROUP BY deptno) d
WHERE e.deptno = d.deptno
AND d.per_num>=4;

EXISTS 关键字

该关键字后面跟一个子查询,用于在 WHERE 中作为过滤条件使用,是用来
判断其后的子查询是否可以查出数据,若可以则 EXISTS 返回true, 否则返回 false

查询有员工的部门

SELECT d.deptno , d.dname, d.loc FROM dept d
WHERE EXISTS(SELECT *FROM emp e
WHERE e.deptno = d.deptno);

查询没有员工的部门

SELECT d.deptno , d.dname, d.loc FROM dept d
WHERE NOT EXISTS(SELECT *FROM emp e
WHERE e.deptno = d.deptno)

查看有下属的员工的工号,名字,职位,工资

SELECT e.empno, e.ename, e.job,e.sal
FROM emp e
WHERE EXISTS(SElECT *FROM emp m WHERE e.empno=m.mgr )

2. 分页查询

  • 分页查询是分段查询数据,在查询的数据量非常大的时候尤其重要.分页查询可以减少,系统资源消耗,响应速度快.
    不同的数据库分页的语法不一致
  • Oracle中使用 ROWNUM 解决分页,
    ROWNUM 是一个伪列,不存在于任何一张表中,但是每张表都可以查询该字段.
    在查询某张表示,只要可以查询出一条记录,该字段的值就是该条记录的行号,从1开始生成的过程在查询过程中进行

举例一:

SELECT ename, sal, deptno FROM
WHERE ROWNUM BETWEEN 6 AND 10

以上查询不出任何数据
原因: 编号是在查询的过程中进行的,所以不能用 ROWNUM 在编号的过程中进行>1以上的数据的判断,否则查询不出数据

正确的做法:

SELECT ename, sal, deptno FROM
(SELECT ROWNUM rn,ename,sal,deptno FROM emp)
WHERE rn BETWEEN 6 AND 10

注意 : 子查询中 ROWNUM 必须要指定别名才能保证外层查询使用的是 子查询中的 ROWNUM

举例二 :
分页与 ORDER BY
查询 工资排名 6 到 10 的员工信息

SELECT * FROM
(SELECT ROWNUM rn ,t.*
FROM (SELECT ename, sal, deptno
FROM emp
ORDER BY sal DESC) t
WHERE ROWNUM <= 10) -- 第10条数据之后不再编号,提高效率
WHERE rn BETWEEN 6 AND 10;

若有排序需求,一定要先排序,因为排序操作是在最后执行的.

计算分页公式

page : 页号
pageSize : 每页的条目数

start : ( page - 1 ) * pageSize + 1

end : pageSize * page


3 . 排序函数

排序函数允许按照指定字段分组, 再按照指定字段排序, 然后生成组内编号


  • ROW_NUMBER ()

生成组内连续且唯一的数字
查看每个部门的工资排名:
SELECT ename, sal, deptno, ROW_NUMBER() OVER(
PARTITION BY deptno
ORDER BY sal DESC
)
FROM emp;


  • RANK ()

生成组内不连续也不唯一的数字
查看每个部门的工资排名(允许相同名次):
SELECT ename, sal, deptno, RANK() OVER(
PARTITION BY deptno
ORDER BY sal DESC
)
FROM emp;


  • DENSE_RANK ()

生成组内连续但不唯一的数字
查看每个部门的工资排名(允许相同名次,但名次不跳跃):
SELECT ename, sal, deptno, DENSE_RANK() OVER(
PARTITION BY deptno
ORDER BY sal DESC
)
FROM emp;

4. DECODE 函数

DECODE 函数用于比较的 参数 1
若匹配 参数 2 则 返回参数 3
若匹配 参数 4 则 返回参数 5
… 最后一个默认值

查询职员的职位来计算奖金

SELECT ename, job , sal, DECODE(job,
'MANAGER',sal*1.2,
'ANALYST',sal*1.1,
'SALESMAN',sal*1.05
) bonus
FROM emp;

计算指定类别职位的人数
如:指定 MANAGER 和 ANALYST 为 VIP , 其他为 OPERATION, 分别统计这两类职位的人数

SELECT DECODE(job,
'ANALYST','VIP',
'MANAGER','VIP',
'OPERATION'
) job,
COUNT(*) job_cnt
FROM emp
GROUP BY DECODE(job,
'ANALYST','VIP',
'MANAGER','VIP',
'OPERATION'
)

5 . 集合操作

  • UNION : 获取结果集并集,并去除重复
  • UNION ALL : 获取结果集并集,但不去重
  • INTERSECT : 获取结果集交集
  • MINUS : 获取结果集的差集(结果集 1 中存在, 结果集 2 中不存在)

示例:(两个查询子句的查询字段必须相同)

SELECT ename,job,sal FROM emp
WHERE job = 'MANAGER'
UNION -- 这里替换其他集合操作
SELECT ename,job,sal FROM emp
WHERE sal>2500

6 . 高级分组函数


  • ROLLUP()

分组情况递减
GROUP BY ROLLUP(a , b , c) 等同于
SELECT... GROUP BY a, b ,c
UNION ALL
SELECT... GROUP BY a, b
UNION ALL
SELECT... GROUP BY a
UNION ALL
全表


  • CUBE()

分组情况全排列
GROUP BY CUBE0(a , b , c) 等同于 (内部实现并非 UNION ALL, 效率更高但效果相同) :
SELECT... GROUP BY a, b , c
UNION ALL
SELECT... GROUP BY a, b
UNION ALL
SELECT... GROUP BY a, c
UNION ALL
SELECT... GROUP BY c
UNION ALL
SELECT... GROUP BY b, c
UNION ALL
SELECT... GROUP BY b
UNION ALL
SELECT... GROUP BY c
UNION ALL
全表


  • GROUPING SETS()

自定义分组
如:
SELECT... GROUP BY GROUPING SETS((year, month), (month))
指定
SELECT... GROUP BY year , month
UNION ALL
SELECT.. GROUP BY month