--合并结果集
--1.union all
SELECT * FROM emp WHERE empno=7369
UNION ALL--单纯合并
SELECT * FROM emp WHERE empno=7369;
--2.union
SELECT * FROM emp WHERE empno=7369
UNION --将重复结果集合并
SELECT * FROM emp WHERE empno=7369;
--------------使用命令窗口执行,查看union与or的执行计划
SQL> alter session set "_b_tree_bitmap_plans" = FALSE;
SQL> explain plan for select empno,ename from emp where empno =7788 or ename='SCOTT';
SQL> select * from table(dbms_xplan.display);
SQL> explain plan for select empno,ename from emp where empno=7788 UNION select empno,ename from emp where ename = 'SCOTT';
SQL> select * from table(dbms_xplan.display);
--可见union会使用索引
--union会强制将结果集进行合并,从而使数据出现错误
SQL> select empno,deptno from emp where mgr=7698 order by 1; EMPNO DEPTNO
----- ------
7499 30
7521 30
7654 30
7844 30
7900 30 SQL> select empno,deptno from emp where job='SALESMAN' order by 1; EMPNO DEPTNO
----- ------
7499 30
7521 30
7654 30
7844 30
--从上面两条语句看出有4条结果重复,看看union和or的区别
SQL> select deptno from emp where mgr=7698 or job='SALESMAN'; DEPTNO
------
30
30
30
30
30 SQL> select deptno from emp where mgr=7698
2 union
3 select deptno from emp where job='SALESMAN'; DEPTNO
------
30
/**************************************************************************************************************************************
* 结论:
* 1.不仅两个数据集间重复的数据会被去重,而且单个数据集里重复的数据也会被去重;
* 2.有重复数据的数据集用union后得到的数据与预期会不一致;
* 3.可以这样,select deptno from (select empno,deptno from emp where mgr=7698 union select empno,deptno from emp where job='SALESMAN')
* 或者将empno改为rowid也行。
**************************************************************************************************************************************/
--4.[inner] join与=
SELECT e.empno,e.ename,d.dname,d.loc
FROM emp e
INNER JOIN dept d ON (e.deptno=d.deptno)
WHERE e.deptno=10;
SELECT e.empno,e.ename,d.dname,d.loc
FROM emp e,dept d
WHERE e.deptno=d.deptno
AND e.deptno=10;--以上两句结果相同,但join是SQL-92标准,可以清晰反应表与表之间的关联关系,推荐使用join
--5.in、exists和inner join
CREATE TABLE emp2 AS--创建相关table
SELECT ename,job,sal,comm FROM emp WHERE job = 'CLERK';
--6.要求查询与emp2相匹配的emp中的数据,可以使用in、exists或inner join
SELECT * FROM emp WHERE (ename,job,sal) IN (SELECT ename,job,sal FROM emp2);
SELECT * FROM emp a WHERE EXISTS (SELECT NULL FROM emp2 b WHERE b.ename=a.ename
AND b.job=a.job
AND b.sal=a.sal);
SELECT * FROM emp a
INNER JOIN emp2 b
ON (b.ename=a.ename
AND b.job=a.job
AND b.sal=a.sal);
/********************************************************************************************************
* 结论:
* 1.以上三条语句可以返回相同条数的结果集;
* 2.通过查看plan可以看出,exists和in都使用了HASH JOIN SEMI(哈希半连接)而inner join使用了哈希连接;
* 3.exists和in的执行效率是一样的,如果不确定,可以通过查看plan来判断,不要死记硬背。
********************************************************************************************************/
--7.内、左、右、外连接
--建立测试表
--左表
DROP TABLE L;
CREATE TABLE L AS SELECT 'L_1' AS str,'' AS v FROM dual UNION ALL
SELECT 'L_2','' AS v FROM dual UNION ALL
SELECT 'L_3','' AS v FROM dual UNION ALL
SELECT 'L_4','' AS v FROM dual;
--右表
DROP TABLE R;
CREATE TABLE R AS
SELECT 'R_3' AS str,'' AS v,1 AS STATUS FROM dual UNION ALL
SELECT 'R_4','' AS v,0 AS STATUS FROM dual UNION ALL
SELECT 'R_5','' AS v,0 AS STATUS FROM dual UNION ALL
SELECT 'R_6','' AS v,0 AS STATUS FROM dual;
--INNER JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
INNER JOIN r ON l.v=r.v
ORDER BY 1,2;
SELECT l.str AS l_str,r.str AS r_str
FROM l,r
WHERE l.v=r.v
ORDER BY 1,2;
--LEFT JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
LEFT JOIN r ON l.v=r.v
ORDER BY 1,2;
SELECT l.str AS l_str,r.str AS r_str
FROM l,r
WHERE l.v=r.v(+)
ORDER BY 1,2;
--RIGHT JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
RIGHT JOIN r ON l.v=r.v
ORDER BY 1,2;
SELECT l.str AS l_str,r.str AS r_str
FROM l,r
WHERE l.v(+)=r.v
ORDER BY 1,2;
--FULL JOIN
SELECT l.str AS l_str,r.str AS r_str
FROM l
FULL JOIN r ON l.v=r.v
ORDER BY 1,2;
--8.自连接
SELECT a.empno,a.ename,b.ename mgr,a.deptno FROM emp a,emp b WHERE a.mgr=b.empno(+) ORDER BY a.empno;
--9.NOT IN,NOT EXISTS和LEFT JOIN
SELECT * FROM DEPT WHERE DEPTNO NOT IN(SELECT DEPTNO FROM EMP WHERE EMP.DEPTNO IS NOT NULL);
SELECT * FROM DEPT WHERE NOT EXISTS (SELECT NULL FROM EMP WHERE EMP.DEPTNO = DEPT.DEPTNO);
SELECT DEPT.* FROM DEPT LEFT JOIN EMP ON EMP.DEPTNO=DEPT.DEPTNO WHERE EMP.DEPTNO IS NULL;
--10.外连接中的条件
--沿用7的测试表,查询左表所有内容,使用V关联右表,但只显示右表中STATUS为1的值,期望结果如下:
STR STR
--- ---
L_1
L_2
L_3 R_3
L_4
--错误写法:
SELECT L.STR,R.STR FROM L LEFT JOIN R ON(L.V=R.V) WHERE R.STATUS=1 ORDER BY 1;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 688663707
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 27 | 8 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 1 | 27 | 8 (25)| 00:00:01 |
|* 2 | HASH JOIN | | 1 | 27 | 7 (15)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| R | 1 | 21 | 3 (0)| 00:00:01 |
| 4 | TABLE ACCESS FULL| L | 4 | 24 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("L"."V"="R"."V")
3 - filter("R"."STATUS"=1)
Note
----- PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
- dynamic sampling used for this statement 21 rows selected
--正确写法:
SELECT L.STR,R.STR FROM L LEFT JOIN R ON (L.V=R.V AND R.STATUS=1) ORDER BY 1;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2310059642
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 108 | 8 (25)| 00:00:01 |
| 1 | SORT ORDER BY | | 4 | 108 | 8 (25)| 00:00:01 |
|* 2 | HASH JOIN OUTER | | 4 | 108 | 7 (15)| 00:00:01 |
| 3 | TABLE ACCESS FULL| L | 4 | 24 | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| R | 1 | 21 | 3 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("L"."V"="R"."V"(+))
4 - filter("R"."STATUS"(+)=1)
Note
----- PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
- dynamic sampling used for this statement 21 rows selected
/*外层条件不要随便加,会影响结果集*/
--11.检测两个表中的数据及对应数据的条数是否相同
CREATE OR REPLACE VIEW V AS
SELECT * FROM EMP WHERE DEPTNO != 10
UNION ALL
SELECT * FROM EMP WHERE ENAME='SCOTT';
--要求查处视图V与表EMP中不同的数据(注意:视图中'SCOTT'有两行数据,而EMP表中只有一条数据)
--分析:除了EMP表中DEPTNO为10的数据,还有ENAME为SCOTT的数据与V中不一致,因为EMP表中只有一条而V中有两条
SELECT *
FROM (SELECT EMPNO,ENAME,COUNT(*) AS CNT FROM V GROUP BY EMPNO,ENAME) V --加一列统计条数用以区分不同
FULL JOIN (SELECT EMPNO,ENAME,COUNT(*) AS CNT FROM EMP GROUP BY EMPNO,ENAME) E
ON V.EMPNO=E.EMPNO AND V.CNT=E.CNT
WHERE V.EMPNO IS NULL OR E.EMPNO IS NULL;
EMPNO ENAME CNT EMPNO ENAME CNT
---------- ---------- ---------- ----- ---------- ----------
7788 SCOTT 2
7782 CLARK 1
7839 KING 1
7788 SCOTT 1
7934 MILLER 1
--12.聚集与内连接
CREATE TABLE EMP_BONUS (EMPNO INT,RECEIVED DATE,TYPE INT);
INSERT INTO EMP_BONUS VALUES (7934,DATE '2005-5-17',1);
INSERT INTO EMP_BONUS VALUES (7934,DATE '2005-2-15',2);
INSERT INTO EMP_BONUS VALUES (7839,DATE '2005-5-17',3);
INSERT INTO EMP_BONUS VALUES (7782,DATE '2005-5-17',1);
--要求返回上述员工的工资及奖金,奖金根据TYPE来定,TYPE为1,奖金为10%...
SELECT E.DEPTNO,E.EMPNO,E.ENAME,E.SAL,B.TYPE*0.1*E.SAL AS BONUS
FROM EMP E,EMP_BONUS B
WHERE E.EMPNO(+)=B.EMPNO;
DEPTNO EMPNO ENAME SAL BONUS
------ ----- ---------- --------- ----------
10 7934 MILLER 1300.00 130
10 7934 MILLER 1300.00 260
10 7839 KING 5000.00 1500
10 7782 CLARK 2450.00 245
--若此时想要计算6月份部门为10的总工资
--错误做法:
SELECT E.DEPTNO,SUM(E.SAL) TOTAL_SAL,SUM(B.TYPE*0.1*E.SAL) AS TOTAL_BONUS
FROM EMP E,EMP_BONUS B
WHERE E.EMPNO(+)=B.EMPNO
GROUP BY E.DEPTNO;
DEPTNO TOTAL_SAL TOTAL_BONUS
------ ---------- -----------
10 10050 2135
--原因,MILLER的工资和奖金都重复计算了,因为他5月份已经降职了,所以有两条不同的TYPE对应他的相关信息!
--正确做法:
SELECT E.DEPTNO,SUM(E.SAL) TOTAL_SAL,SUM(B.TYPE*0.1*E.SAL) AS TOTAL_BONUS
FROM EMP E
INNER JOIN
(SELECT EB.EMPNO,EB.TYPE,EB.RECEIVED
FROM EMP_BONUS EB
INNER JOIN
(SELECT MAX(C.EMPNO) EMPNO,MAX(C.RECEIVED) RECEIVED FROM EMP_BONUS C GROUP BY C.EMPNO) EBG --先统计出员工最新的职位变更时间
ON EB.EMPNO=EBG.EMPNO AND EB.RECEIVED=EBG.RECEIVED) B
ON E.EMPNO=B.EMPNO
GROUP BY E.DEPTNO;
DEPTNO TOTAL_SAL TOTAL_BONUS
------ ---------- -----------
10 8750 1875
--13.聚集与外连接
SELECT E.DEPTNO,SUM(E.SAL) TOTAL_SAL,SUM(B.TYPE*0.1*E.SAL) AS TOTAL_BONUS
FROM EMP E
LEFT JOIN --只改此处为LEFT JOIN即可
(SELECT EB.EMPNO,EB.TYPE,EB.RECEIVED
FROM EMP_BONUS EB
INNER JOIN
(SELECT MAX(C.EMPNO) EMPNO,MAX(C.RECEIVED) RECEIVED FROM EMP_BONUS C GROUP BY C.EMPNO) EBG --先统计出员工最新的职位变更时间
ON EB.EMPNO=EBG.EMPNO AND EB.RECEIVED=EBG.RECEIVED) B
ON E.EMPNO=B.EMPNO
GROUP BY E.DEPTNO
ORDER BY 1;
DEPTNO TOTAL_SAL TOTAL_BONUS
------ ---------- -----------
10 8750 1875
20 10875
30 9400
--14.多表查询时的空值处理
--要求返回比ALLEN提成低的员工
--错误做法:
SELECT E.ENAME,E.COMM
FROM EMP E
WHERE E.COMM<(SELECT COMM FROM EMP WHERE ENAME='ALLEN');
ENAME COMM
---------- ---------
TURNER 0.00
--错误原因:有些员工的COMM一项为NULL,但并未返回
--正确做法:
SELECT E.ENAME,E.COMM
FROM EMP E
WHERE COALESCE(E.COMM,0)<(SELECT COMM FROM EMP WHERE ENAME='ALLEN');
ENAME COMM
---------- ---------
SMITH
JONES
BLAKE
CLARK
SCOTT
KING
TURNER 0.00
ADAMS
JAMES
FORD
MILLER

Oracle查询优化-多表查询的更多相关文章

  1. Oracle查询优化--单表查询

    --查询所有 select * from emp; select * from emp where comm is null; --错误表达 --select * from emp where com ...

  2. Oracle笔记 多表查询

    Oracle笔记  多表查询   本次预计讲解的知识点 1. 多表查询的操作.限制.笛卡尔积的问题: 2. 统计函数及分组统计的操作: 3. 子查询的操作,并且结合限定查询.数据排序.多表查询.统计查 ...

  3. Oracle的多表查询

    多表查询概念: 所谓多表查询,又称表联合查询,即一条语句涉及到的表有多张,数据通过特定的连接进行联合显示. 基本语法: select column_name,.... from table1,tabl ...

  4. oracle SQL多表查询

    SQL多表查询 1.集合理论 1.1 什么是集合 具有某种特定性质的事物的总体. 集合的特性:无序性.互异性.确定性. 一个集合可以小到从一个表中取出一行中的一列.              1 ro ...

  5. mysql 查询优化 ~ 多表查询基础知识

    一 什么是驱动表   1)指定了联接条件时,满足查询条件的记录行数少的表为[驱动表]:   2)未指定联接条件时,行数少的表为[驱动表](Important!).   表现 explain第一行出现的 ...

  6. mysql 查询优化 ~ 多表查询改写思路

    一 简介:在之前我们从基础可知,现在咱们聊一下改写的几种思路二 分类:  1 left join  2 inner join  3 right join三 具体改写思路:思路1 本身不包含子查询,将多 ...

  7. Oracle之多表查询

    -多表查询 1.交叉连接 select * from t_class for update; select * from t_student for update; select for update ...

  8. oracle数据库单表查询

    今天给大家分享的是关于数据库的单表查询,像单表查询/多表查询/分组查询/子查询,这些方法的使用在实际项目过程中会经常用到,作为一名合格的测试人员如果不会数据库那肯定是不行的,行走江湖可能随时会面临被侮 ...

  9. oracle习题-emp表查询练习

    emp表查询练习 1 查询emp表的全部记录 Select * from emp; 2 查询出每个雇员的编号.姓名.基本工资 Select empno,ename,sal from emp; 3 查询 ...

随机推荐

  1. regAsm的历史问题

    regAsm是用来注冊.卸载dll成为通用库的一个工具.关于regAsm的具体资料请參照http://msdn.microsoft.com/en-us/library/tzat5yw6(v=vs.11 ...

  2. 【C语言】调整数组使奇数所有都位于偶数前面(改动)

    //调整数组使奇数全部都位于偶数前面. //输入一个整数数组.实现一个函数,来调整该数组中数字的顺序使得数组中全部的奇数位于数组的前半部分,全部偶数位于数组的后半部分 #include <std ...

  3. php教程之Smarty模板用法实例

    分享下php之Smarty模板的使用方法. 剖析了smarty模板的使用方法,对于学习smarty的朋友有一定的参考价值. 详情如下: 一.模板中的注释每一个Smarty模板文件,都是通过Web前台语 ...

  4. linux修改yum本地源的方法

    CentOS 系统下修改yum本地源: mkdir /mnt/cdrom/ cd /etc/yum.repos.d/mv CentOS-Base.repo CentOS-Base.repo.bakvi ...

  5. RhinoMock学习-Stub方法

    // Arrange var stub = MockRepository.GenerateStub<IDemo>(); stub.Stub(x => x.StringArgStrin ...

  6. 【Android】17.0 第17章 服务绑定—本章示例主界面

    分类:C#.Android.VS2015: 创建日期:2016-03-03 一.简介 通过服务绑定(Bound Services),可以轻松实现后台服务与界面(UI)的交互. 二.本章示例主界面 1. ...

  7. C中的空宏定义,即只有一个参数

    空宏定义的测试代码 #include <stdio.h> #define D(x) int main() { D(printf("null macro")); retu ...

  8. version `GLIBC_2.14' not found 解决方法.

    from http://blog.csdn.net/force_eagle/article/details/8684669 version `GLIBC_2.14' not found 解决方法. 一 ...

  9. 简单好用的hash表-----uthash

    在软件开发中,不可不免的会使用到hash表,hash表的优点这里就不说了,以下介绍一个hash表的C实现, uthash是用宏实现的,使用的时候非常方便,只用包含uthash.h即可. Uthash的 ...

  10. ny17 单调递增最长子序列

    单调递增最长子序列时间限制:3000 ms  |  内存限制:65535 KB难度:4 描述    求一个字符串的最长递增子序列的长度    如:dabdbf最长递增子序列就是abdf,长度为4 输入 ...