天天看點

SQL 基礎6—— 子查詢

/*

一、子查詢

    子查詢就是位于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

      2  where empno = (

      3    select empno from emp

      4    where mgr = 7902 );

    ENAME      JOB

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

    SMITH      CLERK

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

    SQL> select ename,job,sal

      2  from emp

      3  where sal >

      4    (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)

      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子句

         3  where sal >

         4      (select avg(sal)

         6       order by empno);

            order by empno)

       ERROR at line 6:

       ORA-00907: missing right parenthesis

       --子查詢内部沒有傳回行,如下語句可以正确執行,但沒有資料傳回

       SQL> select ename,job

         3  where empno =

         4      (select empno

         6       where mgr = 8000);

       no rows selected

    /* 

六、多行子查詢

    傳回多個行

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

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

    SQL> select empno,ename,job

      3  where sal in

      4      (select max(sal)

      5       from emp

      6       group by deptno);

        EMPNO ENAME      JOB

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

         7698 BLAKE      MANAGER

         7902 FORD       ANALYST

         7788 SCOTT      ANALYST

         7839 KING       PRESIDENT

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

      3  where sal < any

      4      (select avg(sal)

          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

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

      3  where sal > all

      6*      group by deptno)

         7566 JONES      MANAGER

     /*

七、相關子查詢

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

    --查詢工資高于同一部門的員工的部門号,姓名,工資

    SQL> select deptno,ename,sal

      2  from emp outer

      5       from emp inner

      6       where inner.deptno = outer.deptno);

       DEPTNO ENAME             SAL

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

           30 ALLEN            1600

           20 JONES            2975

           30 BLAKE            2850

           20 SCOTT            3000

           10 KING             5000

           20 FORD             3000

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

      3  where exists

      4     (select empno

      5      from emp inner

      6      where inner.mgr = outer.empno);

         7698 BLAKE

         7782 CLARK

         7839 KING

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

    SQL> l3

      3* where exists

    SQL> c /where/where not

      3* where not exists

    SQL> l

      1  select empno,ename

      3  where not exists

      6*     where inner.mgr = outer.empno)

    SQL> /

         7499 ALLEN

         7521 WARD

         7654 MARTIN

         7844 TURNER

         7900 JAMES

         7934 MILLER

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

        EXISTS與IN的不同:

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

        NOT EXISTS 和NOT IN

           當值清單中包含空值的情況下,NOT EXISTS 則傳回true,而NOT IN 則傳回false.

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

    SQL> select deptno,dname,loc

      2  from dept d

      4      (select 1

      5       from emp e

      6*      where e.deptno = d.deptno)

       DEPTNO DNAME          LOC

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

           40 OPERATIONS     BOSTON

    --IN與空值

           SQL> SELECT *

             2    FROM emp e

             3    WHERE e.empno NOT IN (

             4                           SELECT 7369 FROM dual

             5                           UNION ALL

             6                           SELECT NULL FROM dual

             7                          )

             8  ;

           EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO

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

             3    WHERE e.empno IN ('7369',NULL)

             4  ;

            7369 SMITH      CLERK      7902 1980-12-17     800.00               20

    注:子查詢要包含在括号内

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

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

BY。 */

    /*

八、多列子查詢

    1、成對比較

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

    SQL> select * from scott.emp

      2  where (sal,job) in

      3     (select max(sal),job from scott.emp group by job);

        EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO

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

         7934 MILLER     CLERK           7782 23-JAN-82       1300                    10

         7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30

         7839 KING       PRESIDENT            17-NOV-81       5000                    10

         7566 JONES      MANAGER         7839 02-APR-81       2975                    20

         7902 FORD       ANALYST         7566 03-DEC-81       3000                    20

         7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20   

       /*      

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

      2  where sal in (select max(sal) from scott.emp group by job)

      3  and job in (select distinct job from scott.emp);

         7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20

九、嵌套子查詢

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

    SQL> select deptno,Num_emp

      2  from (select deptno,count(empno) as Num_emp from emp group by deptno) d

      3  where Num_emp > 3;

       DEPTNO    NUM_EMP

           30          6

           20          5

    /*     

    注意:子查詢對空值的處理

    除了count(*)外,都會忽略掉空值 */