【网学网提醒】:以下是网学会员为您推荐的SQL子查询,希望本篇文章对您学习有所帮助。
SQL子查询
一、概念:子查询是嵌套在一个select语句中的另一个select语句。当需要从一个表中检索信息,
而检索条件值又是来自该表本身的内部数据时,子查询非常有用。
子查询可以嵌套在一下SQL子句中:where子句、having子句和from子句。
二、规则:1、子查询要用括号括起来。
2、select语句中只能有一个orderby子句,并且它只能是主select语句的最后一个子句。
3、在子查询语句中,只有同时指定了top,才可以指定orderby。
4、如果子查询中含有groupby子句,就不能使用distinct关键字。
5、由子查询创建的视图不能更新。
6、在from子查询中,子查询必须指定别名。
三、类型:
1、单行子查询(即子查询只返回一行结果)
子查询select语句只返回一行结果(单列)。
主查询的where子句使用单行子查询时,返回结果要采用单行比较运算符(=、>、<、>=、<=、<>)。
1.1where子句中使用单行子查询
例1:从雇员表t_emp中查询和雇员tom同部门的雇员、工资和部门编号
useTestDB
go
selecteName,salary,deptNo
fromt_emp
wheredepNo=(selectdepNot_empwhereeName='tom')
go
返回:ENAMESALARYDEPTNO
smith800.000002
tom2000.000002
jack1200.000002
例2:显示和雇员tom从事相同工作,并且工资大于james的雇员、工作和工资
useTestDB
go
selecteName,job,salary
fromt_emp
wherejob=(selectjobfromt_empwhereeName='tom')
andsalary>(selectsalaryfromt_empwhereeName='james')
go
1.2单行子查询中使用聚合函数
例1:显示工资最低的雇员、工作和工资
useTestDB
go
selecteName,job,salary
fromt_emp
wheresalary=(selectmin(salary)fromt_emp)
例2:显示工资高于平均工资的雇员、工作、工资和工资等级
useTestDB
go
selecte.eName,e.job工作,e.salary工资,s.grade工资等级
fromt_empe,t_salgrades
wheree.salary>(selectavg(salary)fromt_emp)
ande.salarybetweens.losalands
.hisal
1.3having子句中使用单行子查询
例1:显示部门内工资比0002部门最低工资要高的部门编号及部门内最低工资
分析:要查询0002部门的最低工资,就要用到min()聚合函数,显然
不能用where子句
要查询符合条件的部门的最低工资,就要用min()聚合函数,
所以必须要有groupby
selectdeptNo部门编号,min(salary)最低工资
fromt_emp
groupbydeptNo
havingmin(salary)>(selectmin(salary)fromt_empwheredeptNo='0002')
例2:查询平均工资最低的工种名称及其平均工资
selectjob工种,avg(salary)平均工资
fromt_emp
groupbyjob
havingmin(salary)=(selectmin(avg(salary))fromt_empgroupbyjob)
2、多行子查询(即子查询只返回多行结果)
子查询select语句返回多行结果(单列)。
主查询的where子句使用多行子查询时,返回结果要采用多行比较运算符(in(notin)、any、all、some)。
多行比较运算符可以和一个或多个值进行比较。
2.1使用in运算符的多行子查询(in运算列符将等于表中的任意一项)
例1:查询有下属的雇员、工作、工资和部门号
selecteName,job,salary,deptNo
fromt_emp
whereempNoin(selectmgrfromt_emp)
扩展:查询没有下属的雇员、工作、工资和部门号
分析:用notin
注意要防止子查询返回空值,因为只要空值成为子查询的一部分,就不能用notin运算符。
所以正确语句如下:selecteName,job,salary,deptNo
fromt_emp
whereemoNonotin(selectnvl(mgr,-1)fromt_emp)//nvl(参数1,参数2)函数是检测mgr是否为空,
空则返回-1,不空返回mgr,参数1和参数2数据类型必须一致。
或:selectmgrfromt_empwheremgrisnotnull
例2:查询各部门中工资最低的员工、工作、工资和部门号
selecteName,job,salary,deptNo
fromt_emp
wheresalaryin(selectmin(salary)fromt_empgroupbydeptNo)
例3:查询与销售部门(SALES)工作相同的其他部门的雇员、工作、工资和部门名
selecte.eName,e.job,e.salary,d.dName
fromt_empe,t_deptd
wheree.deptNo=d.deptNoandd.dName<>'SALES'
andjobin(selectdistincte.jobfromt_empe,t_deptdwheree.deptNo=d.deptNoandd.dName='SALES')
2.2使用any运算符的多行子查询
any运算符将和内部查询返回的结果逐个比较,与单行运算符配合使用
=any:表示可以是子查询返回结果中的任意一个值
>any:表示比子查询返回结果中的最小值大
例1:查询工资低于某个文员(CLERK)雇员工资,但不从事文员工作的雇员编号
、工种和工资
selectempNo,额Name,job,salary
fromt_emp
wheresalary andjob<>'CLERK'
2.3使用all运算符的多行子查询
all运算符将和内部查询返回的每个结果比较
>all:比最大的大
例1:查询高于所有部门平均工资的雇员、工种、工资和部门编号
selecteName,job,salary,deptNo
fromt_emp
wheresalary>all(selectavg(salary)fromt_empgroupbydeptNo)
注:子查询中因为有聚合函数,所以必须用groupby
3、多列子查询(即子查询只返回多列结果)
多列子查询分为:成对比较多列子查询、非成对比较多列子查询
成对比较多列子查询:
例1:查询与部门编号为0003的部门中任意一个雇员的工资和奖金完全相同的雇员、工资、
奖金和部门编号,且该雇员不是来自0003号部门
selecteName,salry,nvl(comm,-1),deptNo
fromt_emp
wheredeptNo<>'0003'
and(salary,nvl(comm,-1))in(selectsalary,nvl(comm,-1)fromt_empwheredeptNo='0003')
非成对比较多列子查询:
例1:查询工资与部门编号为0003的部门中任意一
个雇员的工资相同,同时奖金也与部门编号为0003的部门中
任意一个雇员相同的雇员、工资、奖金和部门编号,且该雇员不是来自0003号部门
selecteName,salary,nvl(comm,-1),deptNo
fromt_emp
wheredeptNo<>'0003'
andsalaryin(selectsalaryfromt_empwheredeptNo=‘0003’)
andnvl(comm,-1)in(selectnvl(comm,-1)fromt_empwheredeptNo='0003')
4、相关子查询(exists、notexists)存在性检查
例1:查询在纽约(NEWYORK)工作的雇员、工种、工资和奖金
selecteName,job,salary,comm
fromt_emp
whereexists(select*fromt_empwheret_emp.deptNo=deptNoandloc=‘NEWYORK’)
5、from子句中使用子查询
在from子句中使用子查询时,必须给子查询指定别名
例1:显示工资高于部门平均工资的雇员、工种、工资和部门号
selecteName,job,salary,deptNo
fromt_emp,(selectdeptNo,avg(salary)avgsalfromt_empgroupbydeptNo)s
wheret_emp.deptNo=s.deptNoandsalary>s.avgsal
例2:查询各部门中工资等级最高的雇员、工种、工资和部门号
方法1:from中使用一个子查询
selecte.eName,e.job,e.salary,s.grade,e.deptNo
fromt_empe,t_salgrades,
(selectmax(s.grade)grade,e.deptNo
fromt_empe,t_salgrades
wheree.salbetweens.losalands.hisal
groupbye.deptNo)t
wheree.salbetweens.losalands.hisal
ande.deptNo=t.deptNoands.grade=t.grade
orderbye.deptNo
方法2:from中使用两个子查询
selectp.eName,p.job,p.salary,p.gradep,p.deptNo
from(
selecte.eName,e.job,e.salary,s.grade,e.deptNo
fromt_empe,t_salgrades
wheree.salbetweens.losalands.hisal
)p,
(
selectmax(s.grade)grade,e.deptNo
fromt_empe,t_salgrades
wheree.salbetweens.losalands.hisal
groupbye.deptNo
)q
wherep.deptNo=q.d
eptNoandp.grade=q.grade
orderbyp.deptNo