SQL教學
SQL RDBMS概念
SQL簡介
SQL NOT NULL約束
SQL DEFAULT約束
SQL唯一約束
SQL主鍵
SQL外鍵
SQL CHECK約束
SQL示例數據庫
SQL索引約束
SQL NULL值
數據庫 - 第一範式(1NF)
數據庫 - 第二範式(2NF)
數據庫 - 第三範式(3NF)
SQL RDBMS數據庫
SQL語法
SQL數據類型
SQL操運算符
SQL算術運算符
SQL比較運算符
SQL邏輯運算符
SQL表達式
SQL創建數據庫(CREATE DATABASE)
SQL丟棄或刪除數據庫(DROP DATABASE)
SQL選擇數據庫(SELECT Database, USE語句)
SQL創建表(CREATE Table)
SQL從現有表創建表
SQL刪除表(DROP或DELETE Table)
SQL INSERT INTO插入查詢
SQL SELECT查詢語句
SQL WHERE子句
SQL AND和OR運算符
SQL UPDATE更新查詢
SQL DELETE刪除查詢
SQL LIKE子句
SQL TOP,LIMIT,ROWNUM子句
SQL ORDER BY排序子句
SQL GROUP BY(分組)
SQL Distinct關鍵字
SQL排序結果
SQL約束
SQL Join聯接
SQL INNER JOIN(內部連接)
SQL LEFT JOIN(左連接)
SQL RIGHT JOIN(右連接)
SQL FULL JOIN(全連接)
SQL自連接
SQL笛卡爾或交叉連接
SQL UNION子句/操作符
SQL INTERSECT子句
SQL EXCEPT子句
SQL別名語法
SQL索引
SQL ALTER TABLE(修改表)
SQL TRUNCATE TABLE(截斷表)
SQL View(視圖)
SQL Having子句
SQL事務
SQL通配符運算符
SQL日期函數
SQL ADDDATE()函數
SQL ADDTIME()函數
SQL CONVERT_TZ()函數
SQL CURDATE()函數
SQL CURRENT_DATE()函數
SQL CURTIME()函數
SQL CURRENT_TIME()函數
SQL CURRENT_TIMESTAMP()方法
SQL DATE(expr)函數
SQL DATEDIFF()方法
SQL DATE_ADD()和DATE_SUB()方法
SQL DATE_FORMAT()函數
SQL DATE_SUB()方法
SQL DAY()函數
SQL DAYNAME()函數
SQL DAYOFMONTH()函數
SQL DAYOFWEEK()函數
SQL DAYOFYEAR()函數
SQL EXTRACT()函數
SQL FROM_DAYS()函數
SQL FROM_UNIXTIME()函數
SQL HOUR()方法
SQL LAST_DAY()函數
SQL LOCALTIME和LOCALTIME()函數
SQL LOCALTIMESTAMP和LOCALTIMESTAMP()函數
SQL MAKEDATE()函數
SQL MAKETIME()函數
SQL MICROSECOND()函數
SQL MINUTE()函數
SQL MONTH()函數
SQL MONTHNAME()函數
SQL NOW()函數
SQL PERIOD_ADD()函數
SQL PERIOD_DIFF()函數
SQL QUARTER()函數
SQL SECOND()函數
SQL SEC_TO_TIME()函數
SQL STR_TO_DATE()函數
SQL SUBDATE()函數
SQL SUBTIME()函數
SQL SYSDATE()函數
SQL TIME()函數
SQL TIMEDIFF()函數
SQL TIMESTAMP()函數
SQL TIMESTAMPADD()函數
SQL TIMESTAMPDIFF()函數
SQL TIME_FORMAT()函數
SQL TIME_TO_SEC()函數
SQL TO_DAYS()函數
SQL UNIX_TIMESTAMP()函數
SQL UTC_DATE()函數
SQL UTC_TIME()函數
SQL UTC_TIMESTAMP()函數
SQL WEEK()函數
SQL WEEKDAY()函數
SQL WEEKOFYEAR()函數
SQL YEAR()函數
SQL YEARWEEK()函數
SQL臨時表
SQL克隆表
SQL子查詢
SQL使用序列(自動遞增)
SQL DISTINCT重複處理
SQL注入
SQL實用函數
SQL MAX()函數
SQL MIN()函數
SQL AVG()函數
SQL SUM()函數
SQL SQRT()函數
SQL RAND()函數
SQL CONCAT()函數
SQL數值函數
SQL ABS()函數
SQL ACOS()函數
SQL ASIN(X)函數
SQL ATAN(X)函數
SQL ATAN2()函數
SQL BIT_AND()函數
SQL BIT_COUNT()函數
SQL BIT_OR()函數
SQL CEIL()函數
SQL CONV()函數
SQL COS()函數
SQL COT()函數
SQL DEGREES()函數
SQL EXP(X)函數
SQL FLOOR(X)函數
SQL FORMAT(X,D)函數
SQL GREATEST()函數
SQL INTERVAL()函數
SQL LEAST()函數
SQL LOG()函數
SQL LOG10(X)函數
SQL MOD()函數
SQL OCT(N)函數
SQL PI()函數
SQL POW()函數
SQL RADIANS()函數
SQL ROUND()函數
SQL SIGN(X)函數
SQL SIN(X)函數
SQL SQRT(X)函數
SQL STD()函數
SQL TAN(X)函數
SQL TRUNCATE()函數
SQL字符串函數
SQL ASCII(str)函數
SQL BIN(N)函數
SQL BIT_LENGTH()函數
SQL CHAR()函數
SQL CHAR_LENGTH()函數
SQL CHARACTER_LENGTH()函數
SQL字符串CONCAT()函數
SQL CONCAT_WS()函數
SQL CONV(N,from_base,to_base)函數
SQL ELT()函數
SQL EXPORT_SET()函數
SQL FIELD()函數
SQL FIND_IN_SET()函數
SQL FORMAT()函數
SQL HEX()函數
SQL INSERT()函數
SQL INSTR()函數
SQL LCASE()函數
SQL LEFT()函數
SQL LENGTH()函數
SQL LOAD_FILE()函數
SQL LOCATE()函數
SQL LOWER()函數
SQL LPAD()函數
SQL LTRIM()函數
SQL MAKE_SET()函數
SQL MID()函數
SQL OCT()函數
SQL OCTET_LENGTH()函數
SQL ORD()函數
SQL POSITION()函數
SQL QUOTE()函數
SQL REGEXP模式
SQL REPEAT()函數
SQL REPLACE()函數
SQL REVERSE()函數
SQL RIGHT()函數
SQL RPAD()函數
SQL SOUNDEX()函數
SQL SPACE()函數
SQL STRCMP()函數
SQL SUBSTRING()函數
SQL SUBSTRING_INDEX()函數
SQL TRIM()函數
SQL UCASE()函數
SQL UNHEX()函數
SQL UPPER()函數

SQL子查詢

在本教程中,您將瞭解SQL子查詢以及如何使用子查詢來形成靈活的SQL語句。

1. SQL子查詢基本

請考慮示例數據庫中的以下員工(employees)和部門(departments)表:

SQL子查詢

假設要查找位置ID爲1700的所有員工,可能會想出以下解決方案。

首先,找到位置ID爲1700的所有部門:

SELECT 
    *
FROM
    departments
WHERE
    location_id = 1700;

執行上面查詢語句,得到以下結果:

+---------------+-----------------+-------------+
| department_id | department_name | location_id |
+---------------+-----------------+-------------+
|             1 | 管理            |        1700 |
|             3 | 採購            |        1700 |
|             9 | 行政人員        |        1700 |
|            10 | 財務            |        1700 |
|            11 | 會計            |        1700 |
+---------------+-----------------+-------------+
5 rows in set

其次,使用上一個查詢的部門ID列表,查找屬於位置ID爲1700的所有員工:

SELECT 
    employee_id, first_name, last_name
FROM
    employees
WHERE
    department_id IN (1 , 3, 8, 10, 11)
ORDER BY first_name , last_name;

執行上面示例代碼,得到以下結果:
SQL子查詢

該解決方案有兩個問題。 首先,查詢departments表以檢查哪個部門屬於位置ID爲1700

由於數據量較小,可以輕鬆獲得部門列表。 但是,在具有大量數據的實際系統中,可能存在問題。

另一個問題是,只要想找到其它位置的員工,就必須修改查詢。
更好的解決方案是使用子查詢。 根據定義,子查詢是嵌套在另一個查詢中的查詢,例如:SELECT,INSERT,UPDATE或DELETE語句。 在本教程中,我們將重點介紹與SELECT語句一起使用的子查詢。

在此示例中,可以重寫上面的兩個查詢,如下所示:

SELECT 
    employee_id, first_name, last_name
FROM
    employees
WHERE
    department_id IN (SELECT 
            department_id
        FROM
            departments
        WHERE
            location_id = 1700)
ORDER BY first_name , last_name;

放在括號內的查詢稱爲子查詢,它也稱爲內部查詢或內部選擇。 包含子查詢的查詢稱爲外部查詢或外部選擇。

要執行查詢,首先,數據庫系統必須執行子查詢並將括號之間的子查詢替換爲其結果 - 位於位置ID爲1700的多個部門ID - 然後執行外部查詢。

可以在許多地方使用子查詢,例如:

  • 使用INNOT IN運算符
  • 比較運算符中
  • 使用EXISTSNOT EXISTS運算符
  • 使用ANYALL運算符
  • FROM子句中
  • SELECT子句中

2. SQL子查詢示例

下面我們舉一些使用子查詢來了解它們如何工作的例子。

2.1. 帶有IN或NOT IN運算符的SQL子查詢

在前面的示例中,已經瞭解了子查詢如何與IN運算符一起使用。 以下示例使用帶有NOT IN運算符的子查詢來查找未找到位置ID爲1700的所有員工:

SELECT 
    employee_id, first_name, last_name
FROM
    employees
WHERE
    department_id NOT IN (SELECT 
            department_id
        FROM
            departments
        WHERE
            location_id = 1700)
ORDER BY first_name , last_name;

執行上面查詢語句,得到以下結果:

+-------------+------------+-----------+
| employee_id | first_name | last_name |
+-------------+------------+-----------+
|         103 | Alexander  | Lee       |
|         193 | Britney    | Zhao      |
|         104 | Bruce      | Wong      |
|         179 | Charles    | Yang      |
|         105 | David      | Liang     |
|         107 | Diana      | Chen      |
|         204 | Hermann    | Wu        |
|         126 | Irene      | Liu       |
|         177 | Jack       | Yang      |
|         145 | John       | Liu       |
|         176 | Jonathon   | Yang      |
|         146 | Karen      | Liu       |
|         178 | Kimberely  | Yang      |
|         120 | Matthew    | Han       |
|         121 | Max        | Han       |
|         201 | Michael    | Zhou      |
|         122 | Min        | Liu       |
|         202 | Pat        | Zhou      |
|         192 | Sarah      | Yang      |
|         123 | Shanta     | Liu       |
|         203 | Susan      | Zhou      |
|         106 | Valli      | Chen      |
+-------------+------------+-----------+
22 rows in set

2.2. 帶有比較運算符的SQL子查詢
以下語法說明了子查詢如何與比較運算符一起使用:

comparison_operator (subquery)

比較運算符是這些運算符之一:

  • 等於(=)
  • 大於(>)
  • 小於(<)
  • 大於或等於(>=)
  • 小於等於(<=)
  • 不相等(!=)或(<>)

以下示例查找薪水最高的員工:

SELECT 
    employee_id, first_name, last_name, salary
FROM
    employees
WHERE
    salary = (SELECT 
            MAX(salary)
        FROM
            employees)
ORDER BY first_name , last_name;

執行上面示例代碼,得到以下結果:

ORDER BY first_name , last_name;
+-------------+------------+-----------+--------+
| employee_id | first_name | last_name | salary |
+-------------+------------+-----------+--------+
|         100 | Steven     | Lee       | 24000  |
+-------------+------------+-----------+--------+
1 row in set

在此示例中,子查詢返回所有員工的最高薪水,外部查詢查找薪水等於最高員工的員工。

以下語句查詢所有薪水都高於的平均薪水的員工:

SELECT 
    employee_id, first_name, last_name, salary
FROM
    employees
WHERE
    salary > (SELECT 
            AVG(salary)
        FROM
            employees);

執行上面查詢語句,得到以下結果:
SQL子查詢

在此示例中,首先,子查詢返回所有員工的平均工資。 然後,外部查詢使用大於運算符來查找工資大於平均值的所有員工。

2.3. 帶有EXISTS或NOT EXISTS運算符的SQL子查詢

EXISTS運算符檢查子查詢返回的行是否存在。 如果子查詢包含任何行,則返回true。 否則,它返回false

EXISTS運算符的語法如下:


EXISTSE  (subquery )

NOT EXISTS運算符與EXISTS運算符相反。

NOT EXISTS (subquery)

以下示例查找至少有一名員工的薪水大於10000的所有部門:

SELECT 
    department_name
FROM
    departments d
WHERE
    EXISTS( SELECT 
            1
        FROM
            employees e
        WHERE
            salary > 10000
                AND e.department_id = d.department_id)
ORDER BY department_name;

執行上面查詢語句,得到以下結果:

SQL子查詢

同樣,以下語句查找所有沒有薪水大於10000的員工的部門:

SELECT 
    department_name
FROM
    departments d
WHERE
    NOT EXISTS( SELECT 
            1
        FROM
            employees e
        WHERE
            salary > 10000
                AND e.department_id = d.department_id)
ORDER BY department_name;

執行上面查詢語句,得到以下結果:

SQL子查詢

2.4. 帶有ALL運算符的SQL子查詢
子查詢與ALL運算符一起使用時的語法如下:

comparison_operator ALL (subquery)

如果x大於子查詢返回的每個值,則以下條件的計算結果爲true

x > ALL (subquery)

例如,假設子查詢返回三個值:1,23。 如果x大於3,則以下條件的計算結果爲true

x > ALL (1,2,3)

以下查詢使用GROUP BY子句和MIN()函數按部門查找最低工資:

SELECT 
    MIN(salary)
FROM
    employees
GROUP BY department_id
ORDER BY MIN(salary) DESC;

執行上面查詢語句,得到以下結果:
SQL子查詢

以下示例查找薪水大於每個部門最低薪水的所有員工:

SELECT 
    employee_id, first_name, last_name, salary
FROM
    employees
WHERE
    salary >= ALL (SELECT 
            MIN(salary)
        FROM
            employees
        GROUP BY department_id)
ORDER BY first_name , last_name;

執行上面查詢語句,得到以下結果:
SQL子查詢

2.5. 帶有ANY運算符的SQL子查詢
以下是帶有ANY運算符的子查詢的語法:

comparison_operator ANY (subquery)

例如,如果x大於子查詢返回的任何值,則以下條件的計算結果爲true。 因此,如果x大於1,則條件x> SOME(1,2,3)的計算結果爲true

x > ANY (subquery)

請注意,SOME運算符是ANY運算符的同義詞,因此可以互換使用它們。

以下查詢查找薪水大於或等於每個部門的最高薪水的所有員工。

SELECT 
    employee_id, first_name, last_name, salary
FROM
    employees
WHERE
    salary >= SOME (SELECT 
            MAX(salary)
        FROM
            employees
        GROUP BY department_id);

執行上面查詢語句,得到以下結果:

+-------------+------------+-----------+--------+
| employee_id | first_name | last_name | salary |
+-------------+------------+-----------+--------+
|         100 | Steven     | Lee       | 24000  |
|         101 | Neena      | Wong      | 17000  |
|         102 | Lex        | Liang     | 17000  |
|         103 | Alexander  | Lee       | 9000   |
|         104 | Bruce      | Wong      | 6000   |
|         105 | David      | Liang     | 4800   |
|         106 | Valli      | Chen      | 4800   |
|         108 | Nancy      | Chen      | 12000  |
... ... 
|         200 | Jennifer   | Zhao      | 4400   |
|         201 | Michael    | Zhou      | 13000  |
|         202 | Pat        | Zhou      | 6000   |
|         203 | Susan      | Zhou      | 6500   |
|         204 | Hermann    | Wu        | 10000  |
|         205 | Shelley    | Wu        | 12000  |
|         206 | William    | Wu        | 8300   |
+-------------+------------+-----------+--------+
31 rows in set

在此示例中,子查詢查找每個部門中員工的最高薪水。 外部查詢查看這些值並確定哪個員工的工資大於或等於按部門劃分的任何最高工資。

2.7. FROM子句中的SQL子查詢

可以在SELECT語句的FROM子句中使用子查詢,如下所示:

SELECT 
    *
FROM
    (subquery) AS table_name

在此語法中,表別名是必需的,因爲FROM子句中的所有表都必須具有名稱。
請注意,FROM子句中指定的子查詢在MySQL中稱爲派生表,在Oracle中稱爲內聯視圖。

以下語句返回每個部門的平均工資:

SELECT 
    AVG(salary) average_salary
FROM
    employees
GROUP BY department_id;

執行上面查詢語句,得到以下結果:
SQL子查詢

可以將此查詢用作FROM子句中的子查詢,以計算部門平均工資的平均值,如下所示:

SELECT 
    ROUND(AVG(average_salary), 0)
FROM
    (SELECT 
        AVG(salary) average_salary
    FROM
        employees
    GROUP BY department_id) department_salary;
+-------------------------------+
| ROUND(AVG(average_salary), 0) |
+-------------------------------+
| 8536                          |
+-------------------------------+
1 row in set

2.8. SELECT子句中的SQL子查詢
可以在SELECT子句中使用表達式的任何位置使用子查詢。 以下示例查找所有員工的工資,平均工資以及每個員工的工資與平均工資之間的差值。

SELECT 
    employee_id,
    first_name,
    last_name,
    salary,
    (SELECT 
            ROUND(AVG(salary), 0)
        FROM
            employees) average_salary,
    salary - (SELECT 
            ROUND(AVG(salary), 0)
        FROM
            employees) difference
FROM
    employees
ORDER BY first_name , last_name;

執行上面查詢語句,得到以下結果 -

+-------------+------------+-----------+--------+----------------+------------+
| employee_id | first_name | last_name | salary | average_salary | difference |
+-------------+------------+-----------+--------+----------------+------------+
|         103 | Alexander  | Lee       | 9000   | 8060           | 940        |
|         115 | Alexander  | Su        | 3100   | 8060           | -4960      |
|         114 | Avg        | Su        | 11000  | 8060           | 2940       |
|         193 | Britney    | Zhao      | 3900   | 8060           | -4160      |
|         104 | Bruce      | Wong      | 6000   | 8060           | -2060      |
|         179 | Charles    | Yang      | 6200   | 8060           | -1860      |
|         109 | Daniel     | Chen      | 9000   | 8060           | 940        |
|         105 | David      | Liang     | 4800   | 8060           | -3260      |
... ... 
|         192 | Sarah      | Yang      | 4000   | 8060           | -4060      |
|         123 | Shanta     | Liu       | 6500   | 8060           | -1560      |
|         205 | Shelley    | Wu        | 12000  | 8060           | 3940       |
|         116 | Shelli     | Zhang     | 2900   | 8060           | -5160      |
|         117 | Sigal      | Zhang     | 2800   | 8060           | -5260      |
|         100 | Steven     | Lee       | 24000  | 8060           | 15940      |
|         203 | Susan      | Zhou      | 6500   | 8060           | -1560      |
|         106 | Valli      | Chen      | 4800   | 8060           | -3260      |
|         206 | William    | Wu        | 8300   | 8060           | 240        |
+-------------+------------+-----------+--------+----------------+------------+
40 rows in set

通過上面的學習,現在您應該瞭解SQL子查詢是什麼,以及如何使用子查詢來形成靈活的SQL語句。