1. 程式人生 > >06. SQL 基礎--> 子查詢

06. SQL 基礎--> 子查詢

多列 urn 位置 sel col 分組函數 數據 lar pda

一、子查詢

子查詢就是位於SELECT、UPDATE、或DELETE語句中內部的查詢

二、子查詢的分類

單行子查詢
    返回零行或一行

多行子查詢
    返回一行或多行

多列子查詢
    返回多列

相關子查詢
    引用外部SQL語句中的一列或多列

嵌套子查詢
    位於其它子查詢中的查詢

  

三、子查詢語法

SELECT select_list
FROM table
WHERE expr operator
   (SELECT select_list
    FROM table);
    
子查詢(內部查詢)在執行主查詢之前執行一次,然後主查詢(外部查詢)會使用該子查詢的結果 

四、子查詢的規則

將子查詢括在括號中
將子查詢放置在比較條件的右側
只有在執行排序Top-N分析時,子查詢中才需要使用ORDER BY 子句
單行運算符用於單行子查詢,多行運算符用於多行子查詢 

五、單行子查詢

僅返回一行
使用單行的表較運算符:= ,>, >= ,< , <= ,<>

在WHERE 子句中使用子查詢 

SQL> select ename,job from emp
     where empno = (
     select empno from emp
     where mgr = 7902 );

ENAME      JOB
---------- ---------
SMITH      CLERK



--使用分組函數的子查詢

SQL> select ename,job,sal
     from emp
     where sal >
     (select avg(sal) from emp);

ENAME      JOB              SAL
---------- --------- ----------
JONES      MANAGER         2975
BLAKE      MANAGER         2850
CLARK      MANAGER         2450
SCOTT      ANALYST         3000
KING       PRESIDENT       5000
FORD       ANALYST         3000



--在HAVING子句中使用子查詢

SQL> select deptno,min(sal)

  2  from emp

  3  group by deptno

  4  having min(sal) >

  5      (select min(sal)

  6       from emp

  7       where deptno = 20);



   DEPTNO   MIN(SAL)

---------- ----------

       30        950

       10       1300

      

--在FROM 子句中使用子查詢

SQL> select empno,ename

  2  from

  3      (select empno,ename

  4       from emp

  5       where deptno = 20);



    EMPNO ENAME

---------- ----------

     7369 SMITH

     7566 JONES

     7788 SCOTT

     7876 ADAMS

     7902 FORD



--單行子查詢中的常見錯誤

    --子查詢的結果返回多於一行

   SQL> select empno,ename

     2  from emp

     3  where sal =

     4      (select sal     

     5       from emp

     6       where deptno = 20);

       (select sal

        *

   ERROR at line 4:

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

  

   --子查詢中不能包含ORDER BY子句

   SQL> select empno,ename

     2  from emp

     3  where sal >

     4      (select avg(sal)

     5       from emp

     6       order by empno);

        order by empno)

        *

   ERROR at line 6:

   ORA-00907: missing right parenthesis

  

   --子查詢內部沒有返回行,如下語句可以正確執行,但沒有數據返回

   SQL> select ename,job

     2  from emp

     3  where empno =

     4      (select empno

     5       from emp

     6       where mgr = 8000);



   no rows selected

  

六、多行子查詢

返回多個行

使用多行比較運算符IN ,ANY ,ALL

在多行子查詢中使用IN 操作符 */

idle> select empno,ename,job
from emp
where sal in
    (select max(sal)
     from emp
     group by deptno);
  2    3    4    5    6  
     EMPNO ENAME      JOB
---------- ---------- ---------
      7698 BLAKE      MANAGER
      7788 SCOTT      ANALYST
      7839 KING       PRESIDENT
      7902 FORD       ANALYST

  

--在多行子查詢中使用ANY 操作符

idle> select empno,ename,job
from emp
where sal < any
    (select avg(sal)
     from emp
     group by deptno);
  2    3    4    5    6  
     EMPNO ENAME      JOB
---------- ---------- ---------
      7369 SMITH      CLERK
      7900 JAMES      CLERK
      7876 ADAMS      CLERK
      7521 WARD       SALESMAN
      7654 MARTIN     SALESMAN
      7934 MILLER     CLERK
      7844 TURNER     SALESMAN
      7499 ALLEN      SALESMAN
      7782 CLARK      MANAGER
      7698 BLAKE      MANAGER

10 rows selected.

  

--在多行子查詢中使用ALL 操作符

idle> select empno,ename,job
from emp
where sal > all
    (select avg(sal)
     from emp
     group by deptno);
  2    3    4    5    6  
     EMPNO ENAME      JOB
---------- ---------- ---------
      7566 JONES      MANAGER
      7788 SCOTT      ANALYST
      7902 FORD       ANALYST
      7839 KING       PRESIDENT

  

/*

七、相關子查詢

子查詢中使用了主查詢中的某些字段,主查詢每掃描一行都要執行一次子查詢 */

--查詢工資高於同一部門的員工的部門號,姓名,工資

idle> select deptno,ename,sal
from emp outer
where sal >
    (select avg(sal)
     from emp inner
     where inner.deptno = outer.deptno);
  2    3    4    5    6  
    DEPTNO ENAME	     SAL
---------- ---------- ----------
	30 ALLEN	    1600
	20 JONES	    2975
	30 BLAKE	    2850
	20 SCOTT	    3000
	10 KING 	    5000
	20 FORD 	    3000

6 rows selected.

--查詢負責管理其它員工的員工記錄(使用exists)

idle> select empno,ename
from emp outer
where exists
   (select empno
    from emp inner
    where inner.mgr = outer.empno);
  2    3    4    5    6  
     EMPNO ENAME
---------- ----------
      7566 JONES
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7902 FORD

6 rows selected.

  

--查詢不管理其它員工的職員(not exists)

idle> select empno,ename
from emp outer
where not exists
(select empno
from emp inner
where inner.mgr = outer.empno);  2    3    4    5    6  

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

8 rows selected.

 

EXISTS 和NOT EXISTS 與IN 和NOT IN 的比較

EXISTS與IN的不同:

EXISTS只檢查行的存在性,IN 要檢查實際值的存在性(一般情況下EXISTS的性能高於IN)

NOT EXISTS 和NOT IN

當值列表中包含空值的情況下,NOT EXISTS 則返回true,而NOT IN 則返回false.

--看下面的查詢,查詢部門號不在emp表中出現的部門名稱及位置

idle> select deptno,dname,loc
from dept d
where not exists
    (select 1
     from emp e
     where e.deptno = d.deptno);
  2    3    4    5    6  
    DEPTNO DNAME	  LOC
---------- -------------- -------------
	40 OPERATIONS	  BOSTON

  

--IN與空值

idle> SELECT *
FROM emp e
WHERE e.empno NOT IN (
                       SELECT 7369 FROM dual
                       UNION ALL
                       SELECT NULL FROM dual
                      );
  2    3    4    5    6    7  
no rows selected

idle> 
idle> SELECT *
  FROM emp e
  WHERE e.empno IN (7369,NULL);
  2    3  
     EMPNO ENAME      JOB           MGR HIREDATE         SAL       COMM    DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7369 SMITH      CLERK          7902 1980-12-17         800            20

註:子查詢要包含在括號內

子查詢一般放在比較條件的右側

除非進行TOP-N 分析,否則不要在子查詢中使用ORDER BY。 */

/*

八、多列子查詢

1、成對比較

查詢工資為部門最高的記錄

idle> select * from scott.emp
where (sal,job) in        
(select max(sal),job from scott.emp group by job);
  2    3  
     EMPNO ENAME      JOB	       MGR HIREDATE	     SAL       COMM	DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7934 MILLER     CLERK	      7782 1982-01-23	    1300		    10
      7499 ALLEN      SALESMAN	      7698 1981-02-20	    1600	300	    30
      7839 KING       PRESIDENT 	   1981-11-17	    5000		    10
      7566 JONES      MANAGER	      7839 1981-04-02	    2975		    20
      7902 FORD       ANALYST	      7566 1981-12-03	    3000		    20
      7788 SCOTT      ANALYST	      7566 1987-04-19	    3000		    20

6 rows selected.

  

2、非成對比較,實現了與上述類似的功能

idle> select * from scott.emp
where sal in (select max(sal) from scott.emp group by job)
and job in (select distinct job from scott.emp);
  2    3  
     EMPNO ENAME      JOB	       MGR HIREDATE	     SAL       COMM	DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7934 MILLER     CLERK	      7782 1982-01-23	    1300		    10
      7499 ALLEN      SALESMAN	      7698 1981-02-20	    1600	300	    30
      7566 JONES      MANAGER	      7839 1981-04-02	    2975		    20
      7788 SCOTT      ANALYST	      7566 1987-04-19	    3000		    20
      7902 FORD       ANALYST	      7566 1981-12-03	    3000		    20
      7839 KING       PRESIDENT 	   1981-11-17	    5000		    10

  

九、嵌套子查詢

即位於子查詢內部的子查詢,嵌套層數最多可達層。然而應盡量避免使用嵌套子查詢,使用表連接的查詢性能會更高

idle> select deptno,Num_emp
from (select deptno,count(empno) as Num_emp from emp group by deptno) d
where Num_emp > 3;
  2    3  
    DEPTNO    NUM_EMP
---------- ----------
	30	    6
	20	    5

註意:子查詢對空值的處理
除了count(*)外,都會忽略掉空值  

06. SQL 基礎--> 子查詢