一、使用子查询:
① 子查询(内部查询)优先执行
② 将步骤①中查询的结果交给父查询(外部查询)使用,用于确认或取消数据

--一、单行子查询
--1.查询出比JONES雇员工资高的其他雇员
SELECT sal FROM emp WHERE ename = 'JONES';--①查询JONES的工资
SELECT ename, sal
  FROM emp
 WHERE sal > (SELECT sal FROM emp WHERE ename = 'JONES');--②查询出比JONES雇员工资高的其他雇员

--2.显示和雇员7369从事相同工作并且工资大于雇员7876的雇员的姓名和工作。
SELECT job FROM emp WHERE empno = 7369;--①查询雇员7369从事的工作
SELECT sal FROM emp WHERE empno = 7876;--②查询雇员7876的工资
SELECT ename, job
  FROM emp
 WHERE job = (SELECT job FROM emp WHERE empno = 7369)
   AND sal > (SELECT sal FROM emp WHERE empno = 7876);--

--子查询中使用组函数
--3.查询工资最低的员工姓名,岗位及工资
SELECT MIN(sal) FROM emp;--①查询最低工资
SELECT ename,job,sal FROM emp WHERE sal = (SELECT MIN(sal) FROM emp);--

--HAVING子句中使用子查询
--4.查询部门最低工资比20部门最低工资高的部门编号及最低工资
SELECT MIN(sal) FROM emp WHERE deptno = 20;--①查询20部门最低工资
SELECT deptno, MIN(sal)
  FROM emp
 GROUP BY deptno
HAVING MIN(sal) > (SELECT MIN(sal) FROM emp WHERE deptno = 20);--

二、子查询包括比较运算符
单行子查询:>       >=      =      <       <=      <>
多行子查询:IN ANY ALL

--二、多行子查询
--1.查询员工工资为各个部门最低工资的员工信息
SELECT empno, ename, sal
  FROM emp
 WHERE sal IN (SELECT MIN(sal) FROM emp GROUP BY deptno);
--2.查询是经理的员工姓名,工资
SELECT * FROM emp WHERE empno IN(SELECT DISTINCT mgr FROM emp);
--3.查询员工工资为各个部门最低工资的员工信息(使用ANY)
SELECT empno, ename, sal
  FROM emp
 WHERE sal = ANY(SELECT MIN(sal) FROM emp GROUP BY deptno);--相当于IN
--4.查询部门编号不为10,且工资比10部门【任意】一名员工工资高的员工编号,姓名,职位,工资
SELECT empno, ename, job, sal
  FROM emp
 WHERE deptno <> 10
   AND sal > ANY (SELECT sal FROM emp WHERE deptno = 10);
--5.查询部门编号不为10,且工资比10部门【所有】一名员工工资低的员工编号,姓名,职位,工资
SELECT empno, ename, job, sal
  FROM emp
 WHERE deptno <> 10
   AND sal < ALL (SELECT sal FROM emp WHERE deptno = 10);

 

三、多列子查询
功能:返回多行多列
通常用多行运算符:IN

--三、多列子查询
--1.查询出和1981年入职的【任意】一个员工的部门和职位【完全相同】员工姓名、部门、职位、入职日期,不包括1981年入职员工
SELECT * FROM emp WHERE hiredate BETWEEN '1-1月-81' AND '31-12月-81';--查询1981年入职的员工
SELECT * FROM emp WHERE TO_CHAR(hiredate,'yyyy') = '1981';--查询1981年入职的员工
SELECT * FROM emp WHERE SUBSTR(hiredate,-2) = '81';--查询1981年入职的员工
SELECT * FROM emp WHERE EXTRACT(YEAR FROM hiredate) = '1981';--查询1981年入职的员工
SELECT ename, deptno, job, hiredate--成对比较
  FROM emp
 WHERE (deptno, job) = ANY
 (SELECT deptno, job FROM emp WHERE SUBSTR(hiredate, -2) = '81')
   AND SUBSTR(hiredate, -2) <> '81';

--2.查询出和1981年入职的【任意】一个员工的【部门或职位相同】员工姓名、部门、职位、入职日期,不包括1981年入职员工
SELECT DISTINCT deptno FROM emp WHERE TO_CHAR(hiredate,'yyyy') = '1981';--①1981年入职员工的部门
SELECT DISTINCT job FROM emp WHERE SUBSTR(hiredate, -2) = '81';--②1981年入职员工的职位
SELECT DISTINCT ename, deptno, job, hiredate--不成对比较
  FROM emp
 WHERE (deptno IN (SELECT DISTINCT deptno
                     FROM emp
                    WHERE TO_CHAR(hiredate, 'yyyy') = '1981') OR
       job IN
       (SELECT DISTINCT job FROM emp WHERE SUBSTR(hiredate, -2) = '81'))
   AND EXTRACT(YEAR FROM hiredate) <> '1981';

 

四、子查询中的NULL值
一般格式:
[列名 | 表达式] IS NOT NULL
作用:
限制列名或表达式不能为空

--四、子查询中的NULL值
--1.查询不是经理的员工姓名,工资
SELECT ename,sal FROM emp WHERE empno NOT IN(SELECT DISTINCT mgr FROM emp WHERE mgr IS NOT NULL);

 

五、在FROM子句使用子查询
一般格式:
SELECT [列名 | *] FROM 子查询 WHERE 限制条件;

--五、在FROM子句中使用子查询
--1.查询比自己部门平均工资高的员工姓名、工资、部门编号、部门平均工资
SELECT deptno,AVG(sal) FROM emp GROUP BY deptno;--查询各部门的平均工资
SELECT ename,sal,e.deptno,avgsal FROM emp e,(SELECT deptno,AVG(sal) avgsal FROM emp GROUP BY deptno) s WHERE e.deptno = s.deptno AND sal > avgsal;

 

六、ROWNUM伪列
注意: 伪列,永远从1开始,rownum只能执行<、<=运算,不能执行>、>=或一个区间运算Between..And等

--六、TOP-N查询
--1.查询工资最高的三个员工的信息
SELECT ROWNUM,e1.* FROM (SELECT emp.* FROM emp WHERE sal IS NOT NULL ORDER BY sal DESC) e1 WHERE ROWNUM <= 3;
--2.查询工资最低的三个员工的信息
SELECT ROWNUM,e1.* FROM (SELECT emp.* FROM emp WHERE sal IS NOT NULL ORDER BY sal) e1 WHERE ROWNUM <= 3;

 

七、数据库的分页查询
开始下标:(当前页码-1)*每页显示条数 + 1
结束下标:每页显示条数 * 当前页码

--七、数据库分页查询
--1.查询第一页数据
SELECT ROWNUM,e.* FROM emp e WHERE ROWNUM <= 5;

--2.查询第二页数据
SELECT e1.* FROM (SELECT ROWNUM rn,e.* FROM emp e WHERE ROWNUM <= 10) e1 WHERE e1.rn >= 6; --效率高,仅查询10条
SELECT e1.* FROM (SELECT ROWNUM rn,e.* FROM emp e) e1 WHERE e1.rn <= 10 AND e1.rn >= 6;    --效率低,永远查询所有数据

--3.查询第三页数据
SELECT e1.* FROM (SELECT ROWNUM rn,e.* FROM emp e WHERE ROWNUM <= 15) e1 WHERE e1.rn >= 11;  --效率高
SELECT e1.* FROM (SELECT ROWNUM rn,e.* FROM emp e) e1 WHERE e1.rn <= 15 AND e1.rn >= 11;     --效率低

--公用的SQL分页查询语句
SELECT e1.* FROM (SELECT ROWNUM rn,e.* FROM emp e WHERE ROWNUM <= &end) e1 WHERE e1.rn >= &begin;

SELECT e1.* FROM (SELECT ROWNUM rn,e.* FROM emp e WHERE ROWNUM <= (每页显示条数 * 当前页码)) e1 WHERE e1.rn >= (当前页码-1)*每页显示条数 + 1);
SELECT e1.* FROM (SELECT ROWNUM rn,e.* FROM emp e) e1 WHERE e1.rn <=(每页显示条数 * 当前页码) AND e1.rn >= (当前页码-1)*每页显示条数 + 1);

--数据分页前,先排序
--1.根据入职日期降序排序后,再分页
SELECT *
  FROM (SELECT ROWNUM rn, e1.*
          FROM (SELECT emp.* FROM emp order by hiredate desc) e1
         WHERE ROWNUM <= 10) e2
 WHERE e2.rn >= 6;