一、使用子查询
- 语法格式
SELECT select_list FROM table WHERE expr operator (SELECT select_list FROM table);
- 括号内的查询叫做子查询,也叫内部查询,先于主查询执行。
- 子查询的结果被主查询(外部查询)使用
- expr operator包括比较运算符。
- 单行运算符:>、=、>=、<、<>、<=
- 多行运算符:IN、ANY、ALL
- 子查询可以嵌于以下SQL语句中
- WHERE子句中
- HAVING子句中
- FROM子句中
- 子查询的使用指导
- 子查询要用括号括起来
- 将子查询放在比较运算符的右边
- 对于单行子查询要使用单行运算符
- 对于多行子查询要使用多行运算符
- 子查询的类型
- 单行子查询
- 多行子查询
- 多列子查询
二、单行子查询
- 子查询只返回一行一列
SELECT ename,job,sal FROM emp WHERE sal = (SELECT sal FROM emp WHERE empno = 7396);
- 使用单行运算符
- 显示和雇员7396从事相同工作并且工资大于雇员7876的员工姓名和工作
SELECT ename, job FROM emp WHERE job = (SELECT job FROM emp WHERE empno = 7369) AND sal > (SELECT sal FROM emp WHERE empno = 7876);
- 在子查询中使用组函数
- 查询工资最低的员工姓名,岗位及工资
SELECT ename,job,sal FROM emp WHERE sal = (SELECT MIN(sal) FROM emp);
- HAVING子句中使用子查询
- 查询部门最低工资比20部门最低工资高的部门编号及最低工资
SELECT deptno,MIN(sal) FROM emp GROUP BY deptno HAVING MIN(sal) > (SELECT MIN(sal) FROM emp WHERE deptno = 20);
- 查询哪个部门的员工人数高于各部门的平均人数。
SELECT deptno,COUNT(empno) FROM emp GROUP BY deptno HAVING COUNT(empno) > (SELECT AVG(COUNT(empno)) FROM emp GROUP BY deptno);
三、多行子查询
- 子查询返回记录的条数,可以是一条或者多条。
- 和多行子查询进行比较时,需要使用多行操作符,多行操作符包括:
- IN
- ANY
- ALL
- IN使用
IN操作符和以前介绍的功能一致,判断是否与子查询的任意一个返回值相同。
- 查询是经理的员工姓名,工资
SELECT ename,sal FROM emp WHERE empno IN (SELECT mgr FROM emp);
- ANY的使用
表示和子查询的任意一个结果进行比较,有一个满足条件即可。
- "< ANY":表示小于子查询结果集中的任意一个,即小于最大值就可以。
- "> ANY":表示大于子查询结果集中的任意一个,即大于最小值就可以。
- "= ANY":表示等于子查询结果集中的任意一个,即等于谁都可以,相当于IN。
- 查询是经理的员工姓名,工资
SELECT ename,sal FROM emp WHERE empno = ANY (SELECT mgr FROM emp);
- 查询部门编号不为10,且工资比10部门任意一名员工工资高的员工编号,姓名,职位,工资。
SELECT empno,name,job,sal FROM emp WHERE sal > ANY(SELECT sal FROM emp WHERE deptno = 10) AND deptno <>10;
- 查询部门编号不为10,且工资比10部门任意一名员工工资低的员工编号,姓名,职位,工资。
SELECT empno,name,job,sal FROM emp WHERE sal < ANY(SELECT sal FROM emp WHERE deptno = 10) AND deptno <> 10;
- ALL的使用
表示和子查询的所有行结果进行比较,每一行都必须满足条件
- "< ALL":表示小于子查询结果集中的所有行,即小于最小值。
- "> ALL":表示大于子查询结果集中的所有行,即大于最大值。
- "= ANL":表示等于子查询结果集中的所有行,即等于所有值,通常来说没有什么实际意义。
- 查询部门编号不为10,且工资比10部门任意一名员工工资高的员工编号,姓名,职位,工资。
SELECT empno,name,job,sal FROM emp WHERE sal > ALL(SELECT sal FROM emp WHERE deptno = 10) AND deptno <>10;
- 查询部门编号不为10,且工资和10部门任意一名员工工资相同的员工编号,姓名,职位,工资。
SELECT empno,name,job,sal FROM emp WHERE sal = ALL(SELECT sal FROM emp WHERE deptno = 10) AND deptno <> 10;
- 查询部门编号不为10,且工资比10部门任意一名员工工资低的员工编号,姓名,职位,工资。
SELECT empno,name,job,sal FROM emp WHERE sal < ALL(SELECT sal FROM emp WHERE deptno = 10) AND deptno <> 10;
四、多列子查询
- 之前讲的子查询都是在一个条件表达式内和子查询的一个列进行比较,多列子查询可以在一个条件表达式内同时和子查询的多个列进行比较。
- 多列子查询通常用IN操作符完成。
- 查询出和1981年入职的任意一个员工的部门和职位完全相同的员工姓名、部门、职位、入职日期,不包括1981年入职员工。
SELECT ename,deptno,job,hiredate FROM emp WHERE (deptno, job) IN (SELECT deptno,job FROM emp WHERE to_char(hiredate,'YYYY')='1981') AND to_char(hiredate,'YYYY')<>'1981';
- 查询出和1981年入职的任意员工的部门或职位相同的员工姓名、部门、职位、入职日期,不包括1981年入职员工。
SELECT ename,deptno,job,hiredate FROM emp WHERE (deptno, job) IN (SELECT deptno,job FROM emp WHERE to_char(hiredate,'YYYY')='1981') AND to_char(hiredate,'YYYY')<>'1981';
五、子查询中的空值
- 所有的条件和空值进行比较结果都是空值。
- 因此,无论什么时候只要空值有可能成为子查询结果集中的一部分,就不能使用NOT IN操作符。
六、在FROM子句中使用子查询
- 查询比自己部门高平均工资高的员工姓名,工资,部门编号,部门平均工资。
SELECT a.ename,a.sal,a.empno,b.salavg FROM emp a, (SELECT deptno,avg(sal) salavg FROM emp GROUP BY deptno) b WHERE a.deptno = b.deptno AND a.sal > b.salavg; //总结:在FROM子句中使用子查询,这个子查询相当于一张表的作用
七、ROWNUM
1.ROWNUM是一个伪列,伪列是使用上类似于表中的列,而实际上并没有存储在表中的特殊列。
2.ROWNUM的功能是在每次查询时,返回结果集的顺序号,这个顺序号是在记录输出时才一步一步产生的,第一行为1,第二行为2,以此类推。SELECT rownum,ename,job FROM emp;
- 在使用ROWNUM时应该注意:
- 1.如下SQL语句,SELECT * FROM emp WHERE ROWNUM > 2查询不到任何记录,因为ROWNUM是在记录输出时才生成的,并且总是从1开始,所以输出的第一条记录不满足>2这个条件,被过滤掉,第二条的ROWNUM又变成了1,又不满足>2的条件,又被过滤掉,依次类推,所以永远没有满足条件的记录,返回空值。所以对于ROWNUM只能够执行<, <=运算,不能执行>, >=或者区间运算BETWEEN ..AND等。
- 2.ROWNUM和ORDER BY一起使用时,因为ROWNUM在记录输出时生成,而ORDER BY子句在最后执行,所以当两者一起使用时,需要注意的是RUWNUM已经是被排过序的ROWNUM了。
八、TOP-N查询
- TOP-N查询主要是实现表中按照某个列排序,输出最大或最小的N条记录。
- 语法
SELECT [列名], ROWNUM FROM (SELECT [列名] FROM 表名 ORDER BY Top-N操作的列 ASC|DESC) WHERE ROWNUM <= N (ASC是查询最小的N条记录,DESC是查询最大的N条记录)
九、分页
- 分页查询
在Oracle中,利用ROWNUM的特性,可实现数据库端的分页查询,查询的语法如下:
- 当未指定需要按照某列排序时,语法为:
SELECT b.* FROM (SELECT ROWNUM rn,[列名1,列名2,....列名n] FROM 表名1,[表名2,...表名n] WHERE [条件表达式 AND ] ROWNUM <=目标页数*每页记录数) b WHERE rn > (目标页数-1)*每页记录数 或 SELECT b.* FROM (SELECT ROWNUM rn,[列名1,列名2,....列名n] FROM 表名1,[表名2,...表名n] [WHERE 条件表达式]) b WHERE rn <=目标页数*每页记录数 and rn > (目标页数-1)*每页记录数
思考:哪种方式效率高?
- 当指定需要按照某列进行排序时,语法为:
SELECT * FROM (SELECT ROWNUM rn, b.* FROM (SELECT 列名1 [,列名2,....列名n] FROM 表名1,[表名2,...表名n] [WHERE 子句] ORDER BY 要排序的列 ASC|DESC ) b WHERE ROWNUM <=目标页数*每页记录数 ) WHERE rn > (目标页数-1)*每页记录数 ; 或: SELECT * FROM (SELECT ROWNUM rn, b.* FROM (SELECT 列名1 [,列名2,....列名n] FROM 表名1,[表名2,...表名n] [WHERE 子句] ORDER BY 要排序的列 ASC|DESC ) b ) WHERE rn <=目标页数*每页记录数 and rn > (目标页数-1)*每页记录数;
网友评论