集合操作包括并(union & union all)、交(intersect)、差(minus)三种,为了合并多个select语句的结果看,可以使用这三处方法实现。其语法如下。
select 语句1
[union | union all | intersect | minus]
select 语句2
1.union和union all操作
union用于获取两个或者多个结果集的并集,当使用该操作符时候,会自动去掉结果集中的重复行
union all 操作符返回查询检索出的所有行,包括重复行。
2.Intersect,对两个结果集进行交集操作,不包括重复行
3.Minus,对两个结果集进行差操作,不包括重复行,返回语句1进行差之后的行
下面例子用来说明union,union all,Intersect,Minus的具体用法
1.基于scott用户下的emp表创建两张测试表
SQL> create table scott.emp_1 as select ename,deptno,sal from scott.emp where deptno=10 or deptno=20;
Table created.
SQL> create table scott.emp_2 as select ename,deptno,sal from scott.emp where deptno=20 or deptno=30;
Table created.
SQL> select * from scott.emp_1;
ENAME DEPTNO SAL
---------- ---------- ----------
SMITH 20 800
JONES 20 2975
CLARK 10 2450
SCOTT 20 3000
KING 10 5000
ADAMS 20 1100
FORD 20 3000
MILLER 10 1300
8 rows selected.
SQL> select * from scott.emp_2;
ENAME DEPTNO SAL
---------- ---------- ----------
SMITH 20 800
ALLEN 30 1600
WARD 30 1250
JONES 20 2975
MARTIN 30 1250
BLAKE 30 2850
SCOTT 20 3000
TURNER 30 1500
ADAMS 20 1100
JAMES 30 950
FORD 20 3000
11 rows selected.
2.现在两张表的20号部门重复,使用union连接查询
SQL> select * from scott.emp_1
2 union
3 select * from scott.emp_2;
ENAME DEPTNO SAL
---------- ---------- ----------
ADAMS 20 1100
ALLEN 30 1600
BLAKE 30 2850
CLARK 10 2450
FORD 20 3000
JAMES 30 950
JONES 20 2975
KING 10 5000
MARTIN 30 1250
MILLER 10 1300
SCOTT 20 3000
ENAME DEPTNO SAL
---------- ---------- ----------
SMITH 20 800
TURNER 30 1500
WARD 30 1250
14 rows selected.
上面结果返回了14行,把两个表中的20号部门重复的行合并返回。
3.用union all查询,如下返回了两个表中的所有数据
SQL> select * from scott.emp_1
2 union all
3 select * from scott.emp_2;
ENAME DEPTNO SAL
---------- ---------- ----------
SMITH 20 800
JONES 20 2975
CLARK 10 2450
SCOTT 20 3000
KING 10 5000
ADAMS 20 1100
FORD 20 3000
MILLER 10 1300
SMITH 20 800
ALLEN 30 1600
WARD 30 1250
ENAME DEPTNO SAL
---------- ---------- ----------
JONES 20 2975
MARTIN 30 1250
BLAKE 30 2850
SCOTT 20 3000
TURNER 30 1500
ADAMS 20 1100
JAMES 30 950
FORD 20 3000
19 rows selected.
注意上面两个不同的查询返回的结果,在排序上有区别,可以看到使用union all是将2个查询语句组合按照原有的顺序返回,而union打乱了这个顺序,如果想使用unio排序,只需要使用order by处理下就可以了,我并没有研究union是使用什么样的规则排序的,这是在实验中得出了这一结论,需要注意order by 应该写在最后一个查询的后面,
4.查询销售部门(SALES),所有雇员的姓名(ENAME)和职位(JOB),以及职位是经理(MANAGER)的所有雇员的姓名和部门名称(dname)
SQL> select ename,dname,job
2 from scott.emp e, scott.dept d
3 where e.deptno=d.deptno and dname='SALES'
4 union
5 select ename,dname,job
6 from scott.emp e, scott.dept d
7 where e.deptno=d.deptno and job='MANAGER'
8 order by dname;
ENAME DNAME JOB
---------- -------------- ---------
CLARK ACCOUNTING MANAGER
JONES RESEARCH MANAGER
ALLEN SALES SALESMAN
BLAKE SALES MANAGER
JAMES SALES CLERK
MARTIN SALES SALESMAN
TURNER SALES SALESMAN
WARD SALES SALESMAN
8 rows selected.
上面的结果BLAKE的雇员既是SLASE的员工,又是部门的MNAGER,他符合了两个查询条件,由于使用了union去掉了重复行,下面是改成union all的返回结果,union all保留了重复行因此BLAKE返回了两行
SQL> select ename,dname,job
2 from scott.emp e, scott.dept d
3 where e.deptno=d.deptno and dname='SALES'
4 union all
5 select ename,dname,job
6 from scott.emp e, scott.dept d
7 where e.deptno=d.deptno and job='MANAGER'
8 order by dname;
ENAME DNAME JOB
---------- -------------- ---------
CLARK ACCOUNTING MANAGER
JONES RESEARCH MANAGER
ALLEN SALES SALESMAN
JAMES SALES CLERK
BLAKE SALES MANAGER
MARTIN SALES SALESMAN
TURNER SALES SALESMAN
WARD SALES SALESMAN
BLAKE SALES MANAGER
5.下面例子是一个我在面试的时候遇到的一个题目,显示emp表中所有雇员的工资,前3名的降序排列,其它的默认不变,这个用union all就可以实现
分析:只需要将前三名的工资查询出来,然后把这个查询的结果当做第二个查询的条件,用union all连接起来就可以了,注意这里不能使用union因为union在执行合并时会打乱排序的顺序,这里是没有重复值的,所以必须要用union all来做处理
SQL> select ename,sal from (select ename,sal from scott.emp order by sal desc) where rownum < 4
2 union all
3 select ename,sal from scott.emp where sal not in(select sal from (select ename,sal from scott.emp order by sal desc) where rownum < 4 );
ENAME SAL
---------- ----------
KING 5000
SCOTT 3000
FORD 3000
SMITH 800
ALLEN 1600
WARD 1250
JONES 2975
MARTIN 1250
BLAKE 2850
CLARK 2450
TURNER 1500
ENAME SAL
---------- ----------
ADAMS 1100
JAMES 950
MILLER 1300
14 rows selected.
6.交(intersect)操作
SQL> select * from scott.emp_1
2 intersect
3 select * from scott.emp_2;
ENAME DEPTNO SAL
---------- ---------- ----------
ADAMS 20 1100
FORD 20 3000
JONES 20 2975
SCOTT 20 3000
SMITH 20 800
结果返回了2个两个表中共有的行
更新20号部门的雇员SMITH的工资,下面的例子返回的结果就不包含SMITH了,可以看出使用intersect操作返回将两个表中共有的字段值合并返回,
SQL> update scott.emp_2 set sal = 1000 where ename='SMITH';
1 row updated.
SQL> commit;
Commit complete.
SQL> select * from scott.emp_2
2 intersect
3 select * from scott.emp_1;
ENAME DEPTNO SAL
---------- ---------- ----------
ADAMS 20 1100
FORD 20 3000
JONES 20 2975
SCOTT 20 3000
7.差(minus)操作
开始还没有做下列查询的时候我非常确定以为会返回10号和30号部门的员工,刚好与intersect想法,结果回显不是这样,如下:
SQL> select * from scott.emp_1
2 minus
3 select * from scott.emp_2;
ENAME DEPTNO SAL
---------- ---------- ----------
CLARK 10 2450
KING 10 5000
MILLER 10 1300
只返回了第一个表中10号部门的员工,于是我就调换了两个表的顺序,返回结果让我一下就明白了
SQL> select * from scott.emp_2
2 minus
3 select * from scott.emp_1;
ENAME DEPTNO SAL
---------- ---------- ----------
ALLEN 30 1600
BLAKE 30 2850
JAMES 30 950
MARTIN 30 1250
SMITH 20 1000
TURNER 30 1500
WARD 30 1250
7 rows selected.
可以看出minus是将第一个表和第二个表相同的值去掉然后返回第一个表的值,如果连接了3个表,也是这一原理只会返回第一个表中在其它任意表中没有的数据