Chapter 07Using Subqueries to Solve Queries

Objectives

After completing this lesson,you should be able to do the following:

  • Define subqueries.
  • Describe the types of problems that the subqueries can solve.
  • List the types of subqueries.
  • Write single-row and multiple-row subqueries.

single-row:查询结果返回一条记录

multiple-row: 查询结果返回多条记录

Lesson Agenda

  • Subquery:Types,syntax,and guidelines
  • Single-row subqueries
    • -Group functions in a subquery
    • -HAVING clause with subqueries
  • Multiple-row subqueries
    • -Use ALL or ANY operator

Using a Subquery to Solve a Problem

Who has a salary greater than Abel`s? 

Demo-01:

Original Query
SQL> SELECT employee_id,first_name,last_name,salary FROM employees WHERE last_name LIKE 'Abel%';

EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        174 Ellen                Abel                           11000

SQL> SELECT employee_id,first_name,last_name,salary FROM employees WHERE salary > 11000;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        201 Michael              Hartstein                      13000
        205 Shelley              Higgins                        12008
        100 Steven               King                           24000
        101 Neena                Kochhar                        17000
        102 Lex                  De Haan                        17000
        108 Nancy                Greenberg                      12008
        145 John                 Russell                        14000
        146 Karen                Partners                       13500
        147 Alberto              Errazuriz                      12000
        168 Lisa                 Ozer                           11500

10 rows selected.

Subquery Syntax

SELECT select_list

FROM table

WHERE expr operator
 
  (SELECT select_list FROM table);
注意:operator的具体值取决于subquery result,视子查询的返回结果集来判断具体使用哪一个Operator.
  • The subquery(inner query) executes before the main query(outer query)
  • The result of the subquery is used by the main query

subquery 一般应用在from where having clause.

Using a Subquery

Subquery
SQL> SELECT employee_id,first_name,last_name,salary
  2  FROM employees
  3  WHERE salary > (SELECT salary FROM employees WHERE last_name LIKE 'Abel%');

EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        201 Michael              Hartstein                      13000
        205 Shelley              Higgins                        12008
        100 Steven               King                           24000
        101 Neena                Kochhar                        17000
        102 Lex                  De Haan                        17000
        108 Nancy                Greenberg                      12008
        145 John                 Russell                        14000
        146 Karen                Partners                       13500
        147 Alberto              Errazuriz                      12000
        168 Lisa                 Ozer                           11500

10 rows selected.
Subquery Error`s Demo
SQL> SELECT employee_id,first_name,last_name,salary
  2  FROM employees
  3  WHERE salary > (SELECT salary FROM employees WHERE last_name LIKE 'K%');
WHERE salary > (SELECT salary FROM employees WHERE last_name LIKE 'K%')
                *
ERROR at line 3:
ORA-01427: single-row subquery returns more than one row

Gudelines for Using Subqueries

  • Enclose subqueries in parentheses.
  • Place subqueries on the right side of the comparison condition for readbility(However,the query can appear on either side of the comparison operator.).
  • Use single-row operators with single-row subqueries and multiple-row operators with multiple-row subqueries.

Types of Subqueries

Single-Row Subqueries

  • Return only one row
  • Use single-row comparison operators
Operator Meaning
= Equal to
> Greater than
>= Greater than or equal to
< Less than
<= Less than or equal to
<> Not equal to
Demo
SQL> SELECT last_name,job_id
  2  FROM employees
  3  WHERE job_id =
  4                 (SELECT job_id
  5                  FROM employees
  6                  WHERE employee_id=141);

LAST_NAME                 JOB_ID
------------------------- ----------
Nayer                     ST_CLERK
Mikkilineni               ST_CLERK
Landry                    ST_CLERK
Markle                    ST_CLERK
Bissot                    ST_CLERK
Atkinson                  ST_CLERK
Marlow                    ST_CLERK
Olson                     ST_CLERK
Mallin                    ST_CLERK
Rogers                    ST_CLERK
Gee                       ST_CLERK

LAST_NAME                 JOB_ID
------------------------- ----------
Philtanker                ST_CLERK
Ladwig                    ST_CLERK
Stiles                    ST_CLERK
Seo                       ST_CLERK
Patel                     ST_CLERK
Rajs                      ST_CLERK
Davies                    ST_CLERK
Matos                     ST_CLERK
Vargas                    ST_CLERK

20 rows selected.

Executing Single-Row Subqueries

View Code
SELECT last_name,job_id,salary
FROM employees
WHERE job_id =  (
                        SELECT job_id
                        FROM employees
                        WHERE last_name = 'Taylor' AND job_id LIKE '%SA_REP%'
                )
AND salary >    (
                        SELECT salary
                        FROM employees
                        WHERE last_name = 'Taylor' AND job_id LIKE '%SA_REP%'

                );
LAST_NAME                 JOB_ID         SALARY
------------------------- ---------- ----------
Tucker                    SA_REP          10000
Bernstein                 SA_REP           9500
Hall                      SA_REP           9000
King                      SA_REP          10000
Sully                     SA_REP           9500
McEwen                    SA_REP           9000
Vishney                   SA_REP          10500
Greene                    SA_REP           9500
Ozer                      SA_REP          11500
Bloom                     SA_REP          10000
Fox                       SA_REP           9600

LAST_NAME                 JOB_ID         SALARY
------------------------- ---------- ----------
Abel                      SA_REP          11000
Hutton                    SA_REP           8800

13 rows selected.

Using Group Functions in a Subqueries

View Code
SELECT last_name,job_id,salary
FROM employees
WHERE salary =  (SELECT MIN(salary) FROM employees );
LAST_NAME                 JOB_ID         SALARY
------------------------- ---------- ----------
Olson                     ST_CLERK         2100

The HAVING Clause with Subqueries

The Oracle server executes the subqueries first.

The Oracle server returns into the HAVING clause of the main query.

View Code
SELECT department_id,min(salary)
FROM employees
GROUP BY department_id
HAVING MIN(salary) >    (
                                SELECT MIN(salary)
                                FROM employees
                                WHERE department_id = 50
                        );
DEPARTMENT_ID MIN(SALARY)
------------- -----------
          100        6900
           30        2500
                     7000
           20        6000
           70       10000
           90       17000
          110        8300
           40        6500
           80        6100
           10        4400
           60        4200

11 rows selected.
Demo 02
SELECT job_id,avg(salary)
FROM employees
GROUP BY job_id
HAVING avg(salary) =    (
                                SELECT min(avg(salary))
                                FROM employees
                                GROUP BY job_id
                        );
JOB_ID     AVG(SALARY)
---------- -----------
PU_CLERK          2780
Wrong Subquery Demo
SELECT employee_id,last_name
FROM employees
WHERE salary = (SELECT MIN(salary) FROM employees GROUP BY department_id);
WHERE salary = (SELECT MIN(salary) FROM employees GROUP BY department_id)
                *
ERROR at line 3:
ORA-01427: single-row subquery returns more than one row

No Rows Returned by the lnner Query

Demo01-仔细对比
SELECT last_name,job_id
FROM employees
WHERE job_id =  (
                        SELECT job_id
                        FROM employees
                        WHERE last_name = 'Hass'
                );  
no rows selected
Demo02-subqueries return null value
SELECT employee_id,last_name,job_id,department_id
FROM employees
WHERE department_id =   (   
                        SELECT department_id
                        FROM employees
                        WHERE last_name = 'Grant' AND job_id = 'SA_REP'
                ); 
no rows selected

Demo02结果分析:subquery result is null value,operator '=' is a arithmeic expression.所以,只要=运算中出现NULL VALUE,那么整个表达式的值,都将为NULL.那么在where子句中,NULL值视同为FALSE.所以整个Main Query的结果为:no rows selected.

Mutltiple-Row Subqueries

  • Return more than one row.
  • Use multiple-row comparison operators
Operator Menaing
IN Equal to any member in the list
ANY Must be preceded by =,!=,>,<,<=,>=.Compares a value to each value in a list or returned by a query.Evaluates to FALUSE if the query returns no rows.
ALL Must be preceded by =,!=,>,<,<=,<=.Compares a value to every value in a list or returned by a query.Evaluates to TRUE if the query returns no rows.

 

 

 

 

Using the ANY Operator in Multiple-Row Subqueries

Any Keyword
SQL> SELECT salary FROM employees WHERE job_id = 'IT_PROG';

    SALARY
----------
      9000
      6000
      4800
      4800
      4200

SQL> SELECT employee_id,last_name,job_id,salary
  2  FROM employees
  3  WHERE salary < ANY (SELECT salary FROM employees WHERE job_id = 'IT_PROG')
  4  AND job_id <> 'IT_PROG';

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        132 Olson                     ST_CLERK         2100
        136 Philtanker                ST_CLERK         2200
        128 Markle                    ST_CLERK         2200
        135 Gee                       ST_CLERK         2400
        127 Landry                    ST_CLERK         2400
        119 Colmenares                PU_CLERK         2500
        191 Perkins                   SH_CLERK         2500
        182 Sullivan                  SH_CLERK         2500
        144 Vargas                    ST_CLERK         2500
        140 Patel                     ST_CLERK         2500
        131 Marlow                    ST_CLERK         2500

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        143 Matos                     ST_CLERK         2600
        118 Himuro                    PU_CLERK         2600
        198 OConnell                  SH_CLERK         2600
        199 Grant                     SH_CLERK         2600
        126 Mikkilineni               ST_CLERK         2700
        139 Seo                       ST_CLERK         2700
        183 Geoni                     SH_CLERK         2800
        195 Jones                     SH_CLERK         2800
        130 Atkinson                  ST_CLERK         2800
        117 Tobias                    PU_CLERK         2800
        134 Rogers                    ST_CLERK         2900

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        116 Baida                     PU_CLERK         2900
        190 Gates                     SH_CLERK         2900
        187 Cabrio                    SH_CLERK         3000
        197 Feeney                    SH_CLERK         3000
        115 Khoo                      PU_CLERK         3100
        196 Walsh                     SH_CLERK         3100
        142 Davies                    ST_CLERK         3100
        181 Fleaur                    SH_CLERK         3100
        194 McCain                    SH_CLERK         3200
        138 Stiles                    ST_CLERK         3200
        125 Nayer                     ST_CLERK         3200

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        180 Taylor                    SH_CLERK         3200
        133 Mallin                    ST_CLERK         3300
        129 Bissot                    ST_CLERK         3300
        186 Dellinger                 SH_CLERK         3400
        141 Rajs                      ST_CLERK         3500
        189 Dilly                     SH_CLERK         3600
        137 Ladwig                    ST_CLERK         3600
        188 Chung                     SH_CLERK         3800
        193 Everett                   SH_CLERK         3900
        192 Bell                      SH_CLERK         4000
        185 Bull                      SH_CLERK         4100

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        184 Sarchand                  SH_CLERK         4200
        200 Whalen                    AD_ASST          4400
        124 Mourgos                   ST_MAN           5800
        202 Fay                       MK_REP           6000
        173 Kumar                     SA_REP           6100
        179 Johnson                   SA_REP           6200
        167 Banda                     SA_REP           6200
        166 Ande                      SA_REP           6400
        123 Vollman                   ST_MAN           6500
        203 Mavris                    HR_REP           6500
        165 Lee                       SA_REP           6800

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        113 Popp                      FI_ACCOUNT       6900
        178 Grant                     SA_REP           7000
        161 Sewall                    SA_REP           7000
        155 Tuvault                   SA_REP           7000
        164 Marvins                   SA_REP           7200
        172 Bates                     SA_REP           7300
        171 Smith                     SA_REP           7400
        160 Doran                     SA_REP           7500
        154 Cambrault                 SA_REP           7500
        111 Sciarra                   FI_ACCOUNT       7700
        112 Urman                     FI_ACCOUNT       7800

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        122 Kaufling                  ST_MAN           7900
        159 Smith                     SA_REP           8000
        120 Weiss                     ST_MAN           8000
        153 Olsen                     SA_REP           8000
        121 Fripp                     ST_MAN           8200
        110 Chen                      FI_ACCOUNT       8200
        206 Gietz                     AC_ACCOUNT       8300
        177 Livingston                SA_REP           8400
        176 Taylor                    SA_REP           8600
        175 Hutton                    SA_REP           8800

76 rows selected.

解读:> ANY就相当于大于子查询中的最小值;

   < ANY就相当于小于子查询中的最大值;

   = ANY就相当于关键字IN;

> ANY
SQL> SELECT employee_id,last_name,job_id,salary
  2  FROM employees
  3  WHERE salary > ANY (SELECT salary FROM employees WHERE job_id = 'IT_PROG');

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        100 King                      AD_PRES         24000
        101 Kochhar                   AD_VP           17000
        102 De Haan                   AD_VP           17000
        145 Russell                   SA_MAN          14000
        146 Partners                  SA_MAN          13500
        201 Hartstein                 MK_MAN          13000
        205 Higgins                   AC_MGR          12008
        108 Greenberg                 FI_MGR          12008
        147 Errazuriz                 SA_MAN          12000
        168 Ozer                      SA_REP          11500
        148 Cambrault                 SA_MAN          11000

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        174 Abel                      SA_REP          11000
        114 Raphaely                  PU_MAN          11000
        162 Vishney                   SA_REP          10500
        149 Zlotkey                   SA_MAN          10500
        169 Bloom                     SA_REP          10000
        156 King                      SA_REP          10000
        150 Tucker                    SA_REP          10000
        204 Baer                      PR_REP          10000
        170 Fox                       SA_REP           9600
        151 Bernstein                 SA_REP           9500
        157 Sully                     SA_REP           9500

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        163 Greene                    SA_REP           9500
        103 Hunold                    IT_PROG          9000
        109 Faviet                    FI_ACCOUNT       9000
        152 Hall                      SA_REP           9000
        158 McEwen                    SA_REP           9000
        175 Hutton                    SA_REP           8800
        176 Taylor                    SA_REP           8600
        177 Livingston                SA_REP           8400
        206 Gietz                     AC_ACCOUNT       8300
        110 Chen                      FI_ACCOUNT       8200
        121 Fripp                     ST_MAN           8200

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        120 Weiss                     ST_MAN           8000
        153 Olsen                     SA_REP           8000
        159 Smith                     SA_REP           8000
        122 Kaufling                  ST_MAN           7900
        112 Urman                     FI_ACCOUNT       7800
        111 Sciarra                   FI_ACCOUNT       7700
        160 Doran                     SA_REP           7500
        154 Cambrault                 SA_REP           7500
        171 Smith                     SA_REP           7400
        172 Bates                     SA_REP           7300
        164 Marvins                   SA_REP           7200

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        155 Tuvault                   SA_REP           7000
        161 Sewall                    SA_REP           7000
        178 Grant                     SA_REP           7000
        113 Popp                      FI_ACCOUNT       6900
        165 Lee                       SA_REP           6800
        123 Vollman                   ST_MAN           6500
        203 Mavris                    HR_REP           6500
        166 Ande                      SA_REP           6400
        167 Banda                     SA_REP           6200
        179 Johnson                   SA_REP           6200
        173 Kumar                     SA_REP           6100

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        202 Fay                       MK_REP           6000
        104 Ernst                     IT_PROG          6000
        124 Mourgos                   ST_MAN           5800
        106 Pataballa                 IT_PROG          4800
        105 Austin                    IT_PROG          4800
        200 Whalen                    AD_ASST          4400

61 rows selected.
= ANY
SQL> SELECT employee_id,last_name,job_id,salary
  2  FROM employees
  3  WHERE salary = ANY (SELECT salary FROM employees WHERE job_id = 'IT_PROG');

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        158 McEwen                    SA_REP           9000
        152 Hall                      SA_REP           9000
        109 Faviet                    FI_ACCOUNT       9000
        103 Hunold                    IT_PROG          9000
        104 Ernst                     IT_PROG          6000
        202 Fay                       MK_REP           6000
        106 Pataballa                 IT_PROG          4800
        105 Austin                    IT_PROG          4800
        184 Sarchand                  SH_CLERK         4200
        107 Lorentz                   IT_PROG          4200

10 rows selected.

Using the ALL Operator in Multiple-Row subqueries

 解读:> ALL就相当于大于子查询中的最大值

      < ALL就相当于小于子查询中的最小值

    没有等于ALL ^^

All Keywords
SQL> SELECT employee_id,last_name,job_id,salary
  2  FROM employees
  3  WHERE salary < ALL (SELECT salary FROM employees WHERE job_id = 'IT_PROG')
  4  AND job_id <> 'IT_PROG';

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        185 Bull                      SH_CLERK         4100
        192 Bell                      SH_CLERK         4000
        193 Everett                   SH_CLERK         3900
        188 Chung                     SH_CLERK         3800
        137 Ladwig                    ST_CLERK         3600
        189 Dilly                     SH_CLERK         3600
        141 Rajs                      ST_CLERK         3500
        186 Dellinger                 SH_CLERK         3400
        133 Mallin                    ST_CLERK         3300
        129 Bissot                    ST_CLERK         3300
        180 Taylor                    SH_CLERK         3200

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        125 Nayer                     ST_CLERK         3200
        138 Stiles                    ST_CLERK         3200
        194 McCain                    SH_CLERK         3200
        115 Khoo                      PU_CLERK         3100
        142 Davies                    ST_CLERK         3100
        196 Walsh                     SH_CLERK         3100
        181 Fleaur                    SH_CLERK         3100
        187 Cabrio                    SH_CLERK         3000
        197 Feeney                    SH_CLERK         3000
        116 Baida                     PU_CLERK         2900
        190 Gates                     SH_CLERK         2900

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        134 Rogers                    ST_CLERK         2900
        195 Jones                     SH_CLERK         2800
        183 Geoni                     SH_CLERK         2800
        117 Tobias                    PU_CLERK         2800
        130 Atkinson                  ST_CLERK         2800
        139 Seo                       ST_CLERK         2700
        126 Mikkilineni               ST_CLERK         2700
        118 Himuro                    PU_CLERK         2600
        199 Grant                     SH_CLERK         2600
        143 Matos                     ST_CLERK         2600
        198 OConnell                  SH_CLERK         2600

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        131 Marlow                    ST_CLERK         2500
        119 Colmenares                PU_CLERK         2500
        191 Perkins                   SH_CLERK         2500
        182 Sullivan                  SH_CLERK         2500
        144 Vargas                    ST_CLERK         2500
        140 Patel                     ST_CLERK         2500
        127 Landry                    ST_CLERK         2400
        135 Gee                       ST_CLERK         2400
        128 Markle                    ST_CLERK         2200
        136 Philtanker                ST_CLERK         2200
        132 Olson                     ST_CLERK         2100

44 rows selected.
> ALL
SQL> SELECT employee_id,last_name,job_id,salary
  2  FROM employees
  3  WHERE salary > ALL (SELECT salary FROM employees WHERE job_id = 'IT_PROG')
  4  AND job_id <> 'IT_PROG';

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        157 Sully                     SA_REP           9500
        151 Bernstein                 SA_REP           9500
        163 Greene                    SA_REP           9500
        170 Fox                       SA_REP           9600
        204 Baer                      PR_REP          10000
        169 Bloom                     SA_REP          10000
        156 King                      SA_REP          10000
        150 Tucker                    SA_REP          10000
        162 Vishney                   SA_REP          10500
        149 Zlotkey                   SA_MAN          10500
        148 Cambrault                 SA_MAN          11000

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        174 Abel                      SA_REP          11000
        114 Raphaely                  PU_MAN          11000
        168 Ozer                      SA_REP          11500
        147 Errazuriz                 SA_MAN          12000
        108 Greenberg                 FI_MGR          12008
        205 Higgins                   AC_MGR          12008
        201 Hartstein                 MK_MAN          13000
        146 Partners                  SA_MAN          13500
        145 Russell                   SA_MAN          14000
        102 De Haan                   AD_VP           17000
        101 Kochhar                   AD_VP           17000

EMPLOYEE_ID LAST_NAME                 JOB_ID         SALARY
----------- ------------------------- ---------- ----------
        100 King                      AD_PRES         24000


23 rows selected.
= ALL (逻辑上是混乱的,但是没有报错)
SQL> SELECT employee_id,last_name,job_id,salary
  2  FROM employees
  3  WHERE salary = ALL (SELECT salary FROM employees WHERE job_id = 'IT_PROG')
  4  AND job_id <> 'IT_PROG';

no rows selected

Null Values in a Subquery

SELECT emp.last_name
FROM employees emp
WHERE emp.employee_id NOT IN
                             (
                                SELECT mgr.manager_id
                                FROM employees mgr
                             );
NULL VALUR -> NOT IN
SQL> SELECT emp.last_name
  2  FROM employees emp
  3  WHERE emp.employee_id NOT IN (SELECT mgr.manager_id FROM employees mgr);

no rows selected
NULL VALUE -> IN
SQL> SELECT emp.last_name
  2  FROM employees emp
  3  WHERE emp.employee_id IN (SELECT mgr.manager_id FROM employees mgr);

LAST_NAME
-------------------------
Cambrault
De Haan
Errazuriz
Fripp
Greenberg
Hartstein
Higgins
Hunold
Kaufling
King
Kochhar

LAST_NAME
-------------------------
Mourgos
Partners
Raphaely
Russell
Vollman
Weiss
Zlotkey

18 rows selected.

NOT IN -> "不等于ALL"

IN -> "等于ANY"

以上两者(NOT IN,IN)在遇上NULL VALUE的时候,表现结果是大相径庭的. 

Summary

In this lesson,you should have learned how to:

  • Identify when a subquery can help solve a problem.
  • Wrtie subqueries when a query is based on unknow values.
SELECT select_list
FROM table
WHERE expr operator
                                (
                                    SELECT select_list
                                    FROM table
                                );
原文地址:https://www.cnblogs.com/arcer/p/3023435.html