子查询是指嵌入在其他SQL语句中的SELECT语句,也称为嵌套查询。注意,当在DDL语句中引用子查询时,可以带有Order By子句;但是当在where子句、Set子句中引用子查询时,不能带有Order by 子句。子查询具有以下一些作用:
1、通过在insert或create table语句中使用子查询,可以将源表数据插入目标表中。
2、通过在create view或create materialieed view中使用子查询,可以定义视图或实体化视图所对应的select语句。
3、通过在update语句中使用子查询可以修改一列或多列数据。
4、通过在where、having、start with子句中使用子查询,可以提供条件值。
根据子查询返回结果的不同,子查询又被分为单行子查询、多行子查询和多列子查询。
一、单行子查询
单行子查询是指只返回一行数据的子查询语句。当在where子句中引用单行子查询时,可以使用单行比较符(=、>、<、>=、<=、<>)。
例:显示JONES同部门的姓名、工资和部门。
sql代码:
SELECT ename,sal,deptno FROM emp WHERE deptno=(SELECT deptno FROM emp WHERE ename='JONES');
二、多行子查询
多行子查询是指返回多行数据的子查询语句。当在where子句中使用多行子查询时必须要使用多行比较符(IN、ALL、ANY)。它们的作用如下:
IN:匹配于子查询结果的任一个值即可。
ALL:必须要符合子查询结果的所有值。
ANY:只要符合子查询结果的任一个值即可。
注意,ALL和ANY操作符不能单独使用,而只能与单行比较符(=,>,<,>=,<=,<>)结合使用。
1、在多行子查询中使用IN操作符
当在多行子查询中使用IN操作符时,会处理匹配于子查询任一值的行。
例:显示与部门10所有员工同工作的雇员名、岗位、工资、部门号的员工。
sql代码:
SELECT ename,job,sal,deptno FROM emp WHERE job IN (SELECT distinct job FROM emp WHERE deptno=10);
2、在多行子查询中使用ALL操作符
ALL操作符必须与单行操作符结合使用,并且返回行必须要匹配于所有子查询结果。
例:显示高于部门30所有雇员工资的雇员名、工资和部门号。
sql代码:
SELECT ename,sal,deptno FROM emp WHERE sal > all (SELECT sal FROM emp where deptno=30);
3、在多行子查询中使用ANY操作符
ANY操作符必须与单行操作符结合使用,并且返回行只需匹配于子查询的任一个结果即可。
例:显示高于部门30的任意雇员工资的雇员名、工资和部门号。
sql代码:
SELECT ename,sal,deptno FROM emp where sal > ANY (SELECT sal FROM emp WHERE deptno=30);
三、多列子查询
单行子查询是指子查询只返回单列单行数据,多行子查询是指子查询返回单列多行数据,二者都是针对单列而言的。而多列子查询则是指返回多列数据的子查询语句。当多列子查询返回单行数据时,在where子句中可以使用单行比较符;当多列子查询返回多行数据时,在where子句中必须使用多行比较符(IN、ANY、ALL)。
例:显示与SMITH部门和岗位完全相同的所有雇员的雇员名,工作岗位、工资和部门号。
SELECT ename,job,sal,deptno FROM emp WHERE (deptno,job) = (SELECT deptno,job FROM emp WHERE ename='SMITH');
在使用子查询比较多个列的数据时,即可以使用成对比较,也可以使用非成对比较。其中,成对比较要求多个列的数据必须同时匹配,而非成对比较则不要求多个列的数据同时匹配。
如下图:
如图所示,当进行成对比较时,要求工资和补助必须同时匹配;而当执行非成对比较时,只要工资匹配于工资列表中的某一个、补助匹配于补助列表中的某一个就可以了。
1、成对比较示例
当执行成对比较时,因为要求多个列的数据必须同时匹配,所以必须要使用多列子查询实现。
例:显示工资和补助与部门30雇员的工资和补助完全匹配的所有雇员。
sql代码:
SELECT ename,sal,comm,deptno FROM emp WHERE (sal,nvl(comm,-1)) IN (SELECT sal,nvl(comm,-1) FROM emp WHERE deptno=30);
2、非成对比较示例
执行非成对比较时,应该要使用多个多行子查询来实现。
例:显示工资匹配于部门30工资列表、补助匹配于部门30补助列表的所有雇员。
sql代码:
SELECT ename,sal,comm,deptno FROM emp WHERE sal IN (SELECT sal FROM emp WHERE deptno=30) AND nvl(comm,-1) IN (select nvl(comm,-1) FROM emp WHERE deptno=30);
四、其他子查询
在where子句中除了可以使用单行子查询、多行子查询以及多列子查询外,还可以用相关子查询。另外在FORM子句、DML语句、DDL语句中也可以使用子查询。
1、相关子查询
相关子查询是指需要引用主查询表列的子查询语句,相关子查询是通过exists谓词来实现的。
例:显示工作在"NEW YORK"的所有雇员。
sql代码:
SELECT ename,job,sal,deptno FROM emp WHERE EXISTS (SELECT 1 FROM dept WHERE dept.deptno=emp.deptno AND dept.loc='NEW YORK');
2、在FROM子句中使用子查询
当在FORM子句中使用子查询时,该子查询会被作为视图对待,因此也被称为内嵌视图。注意,当在FORM子句中使用子查询时,必须给子查询指定别名。
例:显示高于部门平均工资的雇员信息。
sql代码:
SELECT ename,job,sal FROM emp, (SELECT deptno,avg(sal) avgsal FROM emp GROUP BY deptno) dept WHERE emp.deptno=dept.deptno AND sal > dept.avgsal;
3、在DML语句中使用子查询
子查询不仅适于SELECT语句,也适用于任何DML语句。
(1)在insert语句中使用子查询
通过在insert语句中引用子查询,可以将一张表的数据装载到另一张表中去。
例:将EMP表的数据装载到EMPLOYEE表中。
sql代码
INSERT INTO employee(id,name,title,salary) SELECT empno,ename,job,sal FROM emp;
(2)在update语句中使用子查询
当在update语句中使用子查询时,即可以在where子句中引用子查询,也可以在SET子句中使用子查询(修改列数据)。
例:将SMITH同岗位的雇员工资和补助更新为与SMITH的工资和补助完全相同。
sql代码:
UPDATE emp SET (sal,comm)=(SELECT sal,comm FROM emp WHERE ename='SMITH') WHERE job= (SELECT job FROM emp WHERE ename='SMITH');
' (3)在delete语句中使用子查询
在delete语句中使用子查询时,可以在where子句中引用子查询返回未知值。
例:删除SALES部门的所有雇员。
sql代码
DELETE FROM emp WHERE deptno= (SELECT deptno FROM dept WHERE dname='SALES');
4、在DDL语句中使用子查询
除了可以在select、insert、update、delete语句中使用子查询外,也可以在DDL语句中使用子查询。注意,当在select和dml语句中使用子查询时,where子句和set子句的子查询语句不能包含order by子句;但在DDL语句中使用子查询时,子查询可以包含Oorder by 子句。
(1)在create table 语句中使用子查询
通过在create table中使用子查询,可以在建立新表的同时复制表的数据。
例:建立new_emp表,并将emp表的数据复制到该表。
CREATE TABLE new_emp(id,name,sal,job,deptno) AS SELEct empno,ename,sal,job,deptno FROM emp;
(2)在create vies语句中使用子查询
建立视图时,必须指定视图所对应的子查询语句。