ORACLE:子查询

目录

一、单行子查询

使用单行比较操作符 

使用分组函数

子查询使用HAVING

二、多行子查询

 使用IN 和 NOT IN

使用ANY

使用ALL

多列子查询

 在FROM中使用子查询

关联子查询

 在SELECT中使用子查询

使用exists 和 not exists

三、集合运算符

union 并集:排序,去重

 intersect 交集:排序、去重

 minus 差集:排序、去重 

集合运算注意事项 


#测试数据
select * from emp;

     EMPNO ENAME      JOB	       MGR HIREDATE	    SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK	      7902 17-DEC-80	    800 		   20
      7499 ALLEN      SALESMAN	      7698 20-FEB-81	   1600        300	   30
      7521 WARD       SALESMAN	      7698 22-FEB-81	   1250        500	   30
      7566 JONES      MANAGER	      7839 02-APR-81	   2975 		   20
      7654 MARTIN     SALESMAN	      7698 28-SEP-81	   1250       1400	   30
      7698 BLAKE      MANAGER	      7839 01-MAY-81	   2850 		   30
      7782 CLARK      MANAGER	      7839 09-JUN-81	   2450 		   10
      7788 SCOTT      ANALYST	      7566 19-APR-87	   3000 		   20
      7839 KING       PRESIDENT 	   17-NOV-81	   5000 		   10
      7844 TURNER     SALESMAN	      7698 08-SEP-81	   1500 	 0	   30
      7876 ADAMS      CLERK	      7788 23-MAY-87	   1100 		   20
      7900 JAMES      CLERK	      7698 03-DEC-81	    950 		   30
      7902 FORD       ANALYST	      7566 03-DEC-81	   3000 		   20
      7934 MILLER     CLERK	      7782 23-JAN-82	   1300 		   10
      8000 DEBUG

15 rows selected.
select * from dept;

    DEPTNO DNAME	  LOC
---------- -------------- -------------
	10 ACCOUNTING	  NEW YORK
	20 RESEARCH	      DALLAS
	30 SALES	      CHICAGO
	40 OPERATIONS	  BOSTON

子查询举例:

select t.* from (select * from emp order by sal desc) t where rownum<4;

由此可见使用子查询需要注意:

  • 子查询要在括号内,括号内子查询只返回一行
  • 子查询放在比较条件右侧增强可读性
  • 单行操作符对应单行子查询,多行操作符对应多行子查询

一、单行子查询

  • 只返回一行
  • 比较操作符:= > >= < <=  <>(<>不等于,等价于!=) 

使用单行比较操作符 

#例,查询工作与7369相同且工资大于7876的员工信息
select empno,ename,sal from emp where job=(select job from emp where empno=7369) and sal > (select sal from emp where empno=7876);

     EMPNO ENAME	     SAL
---------- ---------- ----------
      7934 MILLER	    1300

使用分组函数

#例 ,查询工资最低的员工
select empno,ename,sal from emp where sal=(select min(sal) from emp);

     EMPNO ENAME	     SAL
---------- ---------- ----------
      7369 SMITH	     800

上述子查询等价于:

select empno,ename,sal from emp order by sal asc fetch first 1 rows only;

子查询使用HAVING

使用HAVING

  • 首先执行子查询
  • 想主查询的having语句返回结果 
#例 查询哪些部门最低工资比20号部门最低工资高
select deptno,min(sal) from emp group by deptno having min(sal) >(select min(sal) from emp where deptno=20);

    DEPTNO   MIN(SAL)
---------- ----------
	30	  950
	10	 1300
# 查询平均工资最高的职位
select job,avg(sal) from emp group by job having avg(sal)=(select max(avg(sal)) from emp group by job);
JOB	    AVG(SAL)
--------- ----------
PRESIDENT	5000
#为了测试子查询,但从结果来说有多种查询方法

注:单行子查询返回有多行结果时,会出错

ORA-01427single-row subquery returns more than one row

二、多行子查询

1、操作符

  • IN 等于列表中的某一个值
  • ANY 与列表的任意值比较
  • ALL 与列表所有值比较

2、返回值多于一行 

 使用IN 和 NOT IN

#查询是领导的员工,mgr存的是员工的领导工号
select empno,ename from emp where empno in (select mgr from emp);

     EMPNO ENAME
---------- ----------
      7566 JONES
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7902 FORD

6 rows selected.

select empno,ename from emp where empno not in (select mgr from emp);

no rows selected

select empno,ename from emp where empno not in (select mgr from emp where mgr is not null);

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7654 MARTIN
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7934 MILLER

8 rows selected.

从上述可知,使用NOT IN时不能对null操作

使用ANY

#查询工资比职位是 clerk 的员工中任意(某)一个低的员工信息
select empno,ename,sal from emp where sal < any (select sal from emp where job='CLERK') and job !='CLERK';

     EMPNO ENAME	     SAL
---------- ---------- ----------
      7521 WARD 	    1250
      7654 MARTIN	    1250

附:

< any :小于最大值

> any :大于最小值

= any :等价于 in

使用ALL

# 例,查询工资比各部门平均工资都高的员工
select empno,ename,sal from emp where sal > all (select avg(sal) from emp group by deptno);

     EMPNO ENAME	     SAL
---------- ---------- ----------
      7566 JONES	    2975
      7788 SCOTT	    3000
      7902 FORD 	    3000
      7839 KING 	    5000

附:

< all :小于最小值

> all :大于最大值

!= all :等价于not  in

多列子查询

例,查询与 7788 号员工 job,sal 相匹配的员工
select empno,ename,sal,job from emp where job=(select job from emp where empno=7788) and sal=(select sal from emp where empno=7788) and empno<>7788;

     EMPNO ENAME	     SAL JOB
---------- ---------- ---------- ---------
      7902 FORD 	    3000 ANALYST
等价于
select empno,ename,sal,job from emp where (job,sal) = (select job,sal from emp where empno=7788) and empno<>7788;

 多行多列子查询要使用多行操作符,如:

select empno,ename,sal,job from emp
where (job,sal) in (select job,sal from emp where deptno=10)   and empno<>7788;

 在FROM中使用子查询

#例:查询比本部门平均工资高的员工
select a.empno,a.ename,a.sal,a.job,a.deptno,b.avgsal from emp a, (select deptno,avg(sal) avgsal from emp group by deptno) b where a.deptno=b.deptno and a.sal > b.avgsal;

     EMPNO ENAME	     SAL JOB	       DEPTNO	  AVGSAL
---------- ---------- ---------- --------- ---------- ----------
      7499 ALLEN	    1600 SALESMAN	   30 1566.66667
      7566 JONES	    2975 MANAGER	   20	    2175
      7698 BLAKE	    2850 MANAGER	   30 1566.66667
      7788 SCOTT	    3000 ANALYST	   20	    2175
      7839 KING 	    5000 PRESIDENT	   10 2916.66667
      7902 FORD 	    3000 ANALYST	   20	    2175

6 rows selected.

关联子查询

普通子查询:在主查询执行之前,子查询首先执行一次。子查询的结果要在主查询中使用。
关联子查询需要重复执行子查询。(where写在子查询中)
#例:查询比本部门平均工资高的员工
select a.empno,a.ename,a.sal,a.deptno from emp a where a.sal > (select avg(sal) from emp b  where a.deptno=b.deptno);

     EMPNO ENAME	     SAL     DEPTNO
---------- ---------- ---------- ----------
      7499 ALLEN	    1600	 30
      7566 JONES	    2975	 20
      7698 BLAKE	    2850	 30
      7788 SCOTT	    3000	 20
      7839 KING 	    5000	 10
      7902 FORD 	    3000	 20

6 rows selected.

 在SELECT中使用子查询

#例:查询员工所属的部门名
select empno,ename,deptno, (select dname from dept d where a.deptno=d.deptno) from emp a;

     EMPNO ENAME	  DEPTNO (SELECTDNAMEFR
---------- ---------- ---------- --------------
      7369 SMITH	      20 RESEARCH
      7499 ALLEN	      30 SALES
      7521 WARD 	      30 SALES
      7566 JONES	      20 RESEARCH
      7654 MARTIN	      30 SALES
      7698 BLAKE	      30 SALES
      7782 CLARK	      10 ACCOUNTING
      7788 SCOTT	      20 RESEARCH
      7839 KING 	      10 ACCOUNTING
      7844 TURNER	      30 SALES
      7876 ADAMS	      20 RESEARCH
      7900 JAMES	      30 SALES
      7902 FORD 	      20 RESEARCH
      7934 MILLER	      10 ACCOUNTING

14 rows selected.

使用exists 和 not exists

#,查询是经理的员工
select a.empno,a.ename from emp a where exists (select 1 from emp b where b.mgr=a.empno);

     EMPNO ENAME
---------- ----------
      7566 JONES
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7902 FORD

6 rows selected.
#,查询不是经理的员工
select a.empno,a.ename from emp a where not exists (select 1 from emp b where b.mgr=a.empno);

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7654 MARTIN
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7934 MILLER

8 rows selected.

三、集合运算符

集合运算符:

  • union 并集:排序、去重
  • intersect 交集:排序、去重
  • minus 差集:排序、去重 
#创建测试表
create table test1 as select * from emp where deptno in (10,20);

Table created.

create table test2 as select * from emp where deptno in (20,30);

Table created.

union 并集排序,去重

select empno,ename,deptno from test1 union select empno,ename,deptno from test2;

     EMPNO ENAME	  DEPTNO
---------- ---------- ----------
      7369 SMITH	      20
      7499 ALLEN	      30
      7521 WARD 	      30
      7566 JONES	      20
      7654 MARTIN	      30
      7698 BLAKE	      30
      7782 CLARK	      10
      7788 SCOTT	      20
      7839 KING 	      10
      7844 TURNER	      30
      7876 ADAMS	      20
      7900 JAMES	      30
      7902 FORD 	      20
      7934 MILLER	      10

14 rows selected.

test1共8条数据,test2共11条数据,union去除了两表中重复的数据,且进行了排序,若不需要去重,使用union all;

select empno,ename,deptno from test1
union all  select empno,ename,deptno from test2;

 intersect 交集:排序、去重

select empno,ename,deptno from test1 intersect select empno,ename,deptno from test2;

     EMPNO ENAME	  DEPTNO
---------- ---------- ----------
      7369 SMITH	      20
      7566 JONES	      20
      7788 SCOTT	      20
      7876 ADAMS	      20
      7902 FORD 	      20
#查询是经理的员工号:
select empno from emp intersect select mgr from emp;

     EMPNO
----------
      7566
      7698
      7782
      7788
      7839
      7902

6 rows selected.

 

 minus 差集:排序、去重 

#test1中有test2中没有的数据:
select ename,deptno from test1 minus select ename,deptno from test2;

ENAME	       DEPTNO
---------- ----------
CLARK		   10
KING		   10
MILLER		   10

#test2中有test1中没有的数据:
select ename,deptno from test2 minus select ename,deptno from test1;

ENAME	       DEPTNO
---------- ----------
ALLEN		   30
BLAKE		   30
JAMES		   30
MARTIN		   30
TURNER		   30
WARD		   30

6 rows selected.

集合运算注意事项 

注:

1、minus要注意操作符前后的表的顺序,如:test1 minus test2:参考test1,test2中没有的;

2、在进行集合运算时,两张表的列名可以不一样,但是数据类型必须一样(可以隐式转换都不行)

3、列column的个数必须一样

4、order by 只能在语句最后出现,且只能按第一个SELECT查询表中的列名来排序

上述第四点如:
alter table test2 rename column deptno to dpn;
select deptno,empno,ename from test1 union select dpn,empno,ename from test2 order by deptno;

    DEPTNO	EMPNO ENAME
---------- ---------- ----------
	10	 7782 CLARK
	10	 7839 KING
	10	 7934 MILLER
	20	 7369 SMITH
	20	 7566 JONES
	20	 7788 SCOTT
	20	 7876 ADAMS
	20	 7902 FORD
	30	 7499 ALLEN
	30	 7521 WARD
	30	 7654 MARTIN
	30	 7698 BLAKE
	30	 7844 TURNER
	30	 7900 JAMES

14 rows selected.
#使用dpn则失败
select deptno,empno,ename from test1 union select dpn,empno,ename from test2 order by dpn;
select deptno,empno,ename from test1 union select dpn,empno,ename from test2 order by dpn
                                                                                      *
ERROR at line 1:
ORA-00904: "DPN": invalid identifier

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值