先看以下子查询的执行顺序:
5select (distinct) 列名【别名】,列名【别名】,
(
5select (distinct) 列名【别名】,列名【别名】
1 from 表名【别名】
2【Where 条件限定】;
3 GROUP BY
4 HAVING 字句
6ORDER BY 列名 ASC/DESC
)
1 from 表名【别名】,表名【别名】,
(
5select (distinct) 列名【别名】,列名【别名】
1 from 表名【别名】
2【Where 条件限定】;
3 GROUP BY
4 HAVING 字句
6ORDER BY 列名 ASC/DESC
)
2【Where 条件限定】,
(
5select (distinct) 列名【别名】,列名【别名】
1 from 表名【别名】
2【Where 条件限定】;
3 GROUP BY
4 HAVING 字句
6ORDER BY 列名 ASC/DESC
)
3 GROUP BY 分组字段,分组字段,
(
5select (distinct) 列名【别名】,列名【别名】
1 from 表名【别名】
2【Where 条件限定】;
3 GROUP BY
4 HAVING 子句
6ORDER BY 列名 ASC/DESC
)
4 HAVING 子句,
(
5select (distinct) 列名【别名】,列名【别名】
1 from 表名【别名】
2【Where 条件限定】;
3 GROUP BY
4 HAVING 字句
6ORDER BY 列名 ASC/DESC
)
6 ORDER BY 列名 ASC/DESC,
(
5select (distinct) 列名【别名】,列名【别名】
1 from 表名【别名】
2【Where 条件限定】;
3 GROUP BY
4 HAVING 字句
6ORDER BY 列名 ASC/DESC
)
子查询都需要使用“()”声明,所谓的子查询就是属于查询嵌套,出现子查询最多的位置:WHERE,FROM;
针对子查询出现给出几个参考方案:
WHERE:子查询返回单行单列,单行多列,多行单列
HAVING:单行单列并且需要统计函数过滤时
FROM:多行多列
SELECT:返回单行单列并且需要某些查询的时候
WHERE:子查询返回单行单列,单行多列,多行单列
WHERE单行单列
例:查找出公司工资最低的雇员信息
--工资最低用MIN()
SELECT MIN(sal) FROM emp;
--统计出最低工资的雇员
SELECT * (雇员信息)
FROM EMP
WHERE sal=(SELECT MIN(sal) FROM emp);
WHERE单行多列(了解)
例:查询出与我们scott工资相同和职位相同的所有雇员信息
--比较工资与职位,同时,先查询scott的工资与职位
SELECT *
FROM emp
WHERE (sal,job)=( SELECT sal,job FROM emp WHERE ename='Scott')
AND ename<>'Scott';
WHERE子查询多行单列(重点)
相当于告诉用户一个数据的操作范围,如果要进行范围的判断,where提供三个运算符,IN,ANY,ALL
1.IN
IN操作指的是内容可以在指定范围内存在
例:查询出与经理职位工资相同的雇员
SELECT * FROM emp
WHERE sal IN
(SELECT sal FROM emp WHERE job='MANAGER');
SELECT * FROM emp
WHERE sal NOT IN--不能为空
(SELECT sal FROM emp WHERE job='MANAGER');
NOT IN不能为空的概念在这里也适用,例如 SELECT * FROM emp WHERE comm NOT IN (SELECT comm FROM emp);--这个操作必须保证子查询SELECT comm FROM emp里面没有空,不然会出现未返回值的情况;
ANY操作
=ANY
SELECT * FROM emp
WHERE sal =ANY
(SELECT sal FROM emp WHERE job='MANAGER');
>ANY:比子查询中最小的查询要大
SELECT * FROM emp
WHERE sal >ANY
(SELECT sal FROM emp WHERE job='MANAGER');
<ANY:比子查询中最大的值要小
SELECT * FROM emp
WHERE sal <ANY
(SELECT sal FROM emp WHERE job='MANAGER');
ALL操作
>ALL比子查询中返回的最大的值要大
<ALL比子查询中返回的最小的值要小
exists()判断
SELECT * FROM emp
WHERE EXISTS
(SELECT * FROM emp WHERE empno=7389);--如果有数据返回就返回SELECT * FROM emp
如果SELECT * FROM emp WHERE empno=7389是有数据的,则使用exists后的子查询是会显示数据出来的;EXISTS之关系子查询里面返回的是否有行,至于什么行不关系。
HAVING:单行单列并且需要统计函数过滤时
必须要结合GROUP BY字句,
例:要求统计出所有高于公司平均工资的部门编号,平均工资及部门人数;
--先统计出根据部门编号的平均工资和部门人数
SELECT deptno,COUNT(*),AVG(sal)
FROM emp
GROUP BY deptno;
--再统计出公司平均工资
SELECT AVG(sal) FROM emp;--子查询单行单列涉及到WHERE和HAVING字句
--因涉及统计函数过滤,要用HAVING
SELECT deptno,COUNT(*),AVG(sal)
FROM emp
GROUP BY deptno
HAVING AVG(sal)>( SELECT AVG(sal) FROM emp);
SELECT:返回单行单列并且需要某些查询的时候
多表查询可以用子查询:
查询雇员名称、职位、部门名称
SELECT e.ename,e.job,d.dname
FROM emp e,dept d
WHERE e.deptno=d.deptno;
转换为
SELECT e.ename,e.job,(SELECT dname FROM dept d WHERE d.deptno=e.deptno)
FROM emp e;
FROM:多行多列(重点)
例:查询每个部门的编号、名称、位置、部门人数、平均工资
SELECT d.deptno,d.dname,d.loc,COUNT(e.empno),AVG(e.sal) --只能出现分组字段d.deptno,d.dname,d.loc
FROM emp e,dept d
WHERE e.deptno(+)=d.deptno
GROUP BY d.deptno,d.dname,d.loc;
利用子查询:
-先查出部门编号、部门人数、平均工资
SELECT d.deptno,COUNT(empno),AVG(sal)
FROM emp
GROUP BY deptno;---当做一张多行多列的表,可作为FROM字句
--利用以上作为字句:
SELECT d.dname,d.loc,d.deptno,temp.count,temp.avg
FROM dept d,(
SELECT d.deptno,COUNT(empno) count,AVG(sal) avg
FROM emp
GROUP BY deptno) temp
WHERE d.deptno=temp.deptno(+);
复杂查询案例:
1.列出薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金,部门名称,部门人数;
--确定要使用的数据表
emp表:员工姓名和薪金
dept表:部门名称
统计函数:部门人数
--确定关联字段
emp.deptno=dept.deptno;
--找出部门30所有员工的薪金,可以得出这是个多行单列的子查询操作,如果要进行范围的判断,where提供三个运算符,IN,ANY,ALL;
--如果案例中出现高于、低于、大于、小于、等于等字眼,则可考虑范围查询,使用WHERE字句和运算符,并且先将范围列出来:在部门30工作的所有员工的薪金
SELECT sal
FROM emp
WHERE deptno=30;
--薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金
SELECT e.sal,e.ename
FROM emp e
WHERE e.sal>ALL(
SELECT sal
FROM emp
WHERE deptno=30) temp;
-- 薪金高于在部门30工作的所有员工的薪金的员工姓名和薪金,部门名称;
SELECT e.sal,e.ename,d.dname
FROM emp e,dept d
WHERE e.sal>ALL(
SELECT sal
FROM emp
WHERE deptno=30)
AND e.deptno=d.deptno;
--统计出部门人数的信息;要按照部门分组,使用分组GROUP BY时SELECT字句只能出现分组字段和统计函数,但是此时SELECT字句出现了其他字段e.sal,e.ename,d.dname,只能考虑子查询,即用FROM中使用字查询得出新的一张表;
SELECT e.sal,e.ename,d.dname,temp.count
FROM emp e,dept d,(
SELECT deptno dno,COUNT(empno) count
FROM emp
GROUP BY deptno) temp
WHERE e.sal>ALL(
SELECT sal
FROM emp
WHERE deptno=30)
AND e.deptno=d.deptno
AND d.deptno=temp.dno;
2.列出与‘Scott'从事相同工作的所有员工及部门名称、部门人数、领导姓名
--确定要使用的数据表
emp表:员工信息
dept表:部门名称
emp表:领导信息
统计函数:部门人数
--确定关联字段
雇员与emp.deptno=dept.deptno;
雇员与领导:emp.mgr(领导编号)=memp.empno;
empno(雇员编号)
mgr(领导编号)
--列出Scott从事的工作,单行单列,只能在WHERE 或Having中使用
SELECT job
FROM emp
WHERE ename='Scott';
--与‘Scott'从事相同工作的所有员工名称及所在部门名称、部门人数、领导姓名
SELECT e.ename,d.dname,temp1.count,m.ename
FROM emp e,dept d,(
SELECT deptno dno,COUNT(empno) count FROM emp
GROUP BY deptno) temp1,emp m
WHERE job=(
SELECT job
FROM emp
WHERE ename='Scott')
AND e.ename<>'Scott'
AND e.deptno=d.deptno
AND d.deptno=temp1.dno
AND e.mgr=m.empno;
3.列出薪金比‘Smith’或‘ALLEN’多的所有员工的编号、姓名、部门名称、其领导姓名、部门人数,平均工资,最高及最低工资;
--数据表:emp表、dept表,统计函数包括部门人数,平均工资,最高及最低工资;
#查出‘Smith’或‘ALLEN’的薪金,多行单列
SELECT sal
FROM emp
WHERE ename IN('SMITH','ALLEN');
#查出比‘Smith’或‘ALLEN’任意一个多的员工信息并抛出‘Smith’和‘ALLEN’,e.mgr=m.empno查询领导姓名
SELECT e.name,e.empno,e.sal,d.dname,m.ename,temp.count,temp.avg,temp.max
FROM emp e,dept d,emp m,(
SELECT deptno dno,COUNT(empno) count AVG(sal) avg ,MAX(sal) max
FROM emp
GROUP BY deptno) temp
WHERE e.sal> ANY(
SELECT sal
FROM emp
WHERE ename IN('SMITH','ALLEN'))
AND e.ename NOT IN('SMITH','ALLEN')
AND e.deptno=d.deptno
AND e.mgr=m.empno(+)
AND temp.dno=d.deptno;
4.找出职位为‘CLERK'的员工编号、姓名、所在部门名称、部门人数、工资等级
SELECT e.name,e.empno,d.name,temp.count,s.grade
FROM emp e,dept d,(
SELECT deptno dno,COUNT(empno)
FROM emp
GROUP BY deptno) temp,salegrade s
WHERE e.job='CLERK'
AND e.deptno=d.deptno
AND d.deptno=temp.dno
AND e.sal BETWEEN s.losal AND s.hisal;