天天看點

什麼是 SQL 子查詢,如何使用 SQL 子查詢

文章目錄

    • 一、子查詢
    • 二、利用子查詢進行過濾
    • 三、作為計算字段使用子查詢
    • 四、小結

本文介紹什麼是 SQL 子查詢,如何使用它們。子查詢常用于

WHERE

子句的

IN

操作符中,以及用來填充計算列。

一、子查詢

SELECT

語句是 SQL 的查詢。我們迄今為止所看到的所有

SELECT

語句都是簡單查詢,即從單個資料庫表中檢索資料的單條語句。

查詢(query)

任何 SQL 語句都是查詢。但此術語一般指

SELECT

語句。

SQL 還允許建立

子查詢

(subquery),即嵌套在其他查詢中的查詢。為什麼要這樣做呢?了解這個概念的最好方法是考察幾個例子。

二、利用子查詢進行過濾

訂單存儲在兩個表中。每個訂單包含訂單編号、客戶

ID

、訂單日期,在

Orders

表中存儲為一行。各訂單的物品存儲在相關的

OrderItems

表中。

Orders

表不存儲顧客資訊,隻存儲顧客

ID

。顧客的實際資訊存儲在

Customers

表中。

現在,假如需要列出訂購物品

RGAN01

的所有顧客,應該怎樣檢索?下面列出具體的步驟。

(1) 檢索包含物品

RGAN01

的所有訂單的編号。

(2) 檢索具有前一步驟列出的訂單編号的所有顧客的

ID

(3) 檢索前一步驟傳回的所有顧客

ID

的顧客資訊。

上述每個步驟都可以單獨作為一個查詢來執行。可以把一條

SELECT

語句傳回的結果用于另一條

SELECT

語句的

WHERE

子句。

也可以使用子查詢來把 3 個查詢組合成一條語句。

第一條

SELECT

語句的含義很明确,它對

prod_id

RGAN01

的所有訂單物品,檢索其

order_num

列。輸出列出了兩個包含此物品的訂單:

SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01';
           

輸出:

order_num
-----------
20007
20008
           

現在,我們知道了哪個訂單包含要檢索的物品,下一步查詢與訂單

20007

20008

相關的顧客

ID

。利用 如何使用 SQL AND、OR、IN 和 NOT 過濾傳回的資料 介紹的

IN

子句,編寫如下的

SELECT

語句:

SELECT cust_id
FROM Orders
WHERE order_num IN (20007,20008);
           

輸出:

cust_id
----------
1000000004
1000000005
           

現在,結合這兩個查詢,把第一個查詢(傳回訂單号的那一個)變為子查詢。請看下面的

SELECT

語句:

SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
                    FROM OrderItems
                    WHERE prod_id = 'RGAN01');
           

輸出:

cust_id
----------
1000000004
1000000005
           

SELECT

語句中,子查詢總是從内向外處理。在處理上面的

SELECT

語句時,DBMS 實際上執行了兩個操作。

首先,它執行下面的查詢:

此查詢傳回兩個訂單号:

20007

20008

。然後,這兩個值以

IN

操作符要求的逗号分隔的格式傳遞給外部查詢的

WHERE

子句。外部查詢變成:

可以看到,輸出是正确的,與前面寫死

WHERE

子句所傳回的值相同。

提示:格式化 SQL

包含子查詢的

SELECT

語句難以閱讀和調試,它們在較為複雜時更是如此。如上所示,把子查詢分解為多行并進行适當的縮進,能極大地簡化子查詢的使用。

順便一提,這就是顔色編碼起作用的地方,好的 DBMS 用戶端正是出于這個原因使用了顔色代碼 SQL。

現在得到了訂購物品

RGAN01

的所有顧客的

ID

。下一步是檢索這些顧客

ID

的顧客資訊。檢索兩列的 SQL 語句為:

SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (1000000004,1000000005);
           

可以把其中的

WHERE

子句轉換為子查詢,而不是寫死這些顧客

ID

SELECT cust_name, cust_contact
FROM Customers
WHERE cust_id IN (SELECT cust_id
                  FROM Orders
                  WHERE order_num IN (SELECT order_num
                                      FROM OrderItems
                                      WHERE prod_id = 'RGAN01'));
           

輸出:

cust_name                         cust_contact
-----------------------------     --------------------
Fun4All                           Denise L. Stephens
The Toy Store                     Kim Howard
           

為了執行上述

SELECT

語句,DBMS 實際上必須執行三條

SELECT

語句。最裡邊的子查詢傳回訂單号清單,此清單用于其外面的子查詢的

WHERE

子句。

外面的子查詢傳回顧客

ID

清單,此顧客

ID

清單用于最外層查詢的

WHERE

子句。最外層查詢傳回所需的資料。

可見,在

WHERE

子句中使用子查詢能夠編寫出功能很強且很靈活的 SQL 語句。對于能嵌套的子查詢的數目沒有限制,不過在實際使用時由于性能的限制,不能嵌套太多的子查詢。

注意:隻能是單列

作為子查詢的

SELECT

語句隻能查詢單個列。企圖檢索多個列将傳回錯誤。

注意:子查詢和性能

這裡給出的代碼有效,并且獲得了所需的結果。但是,使用子查詢并不總是執行這類資料檢索的最有效方法。更多的論述,請參閱 如何使用 SQL INNER JOIN 聯結兩個或多個表,其中将再次給出這個例子。

三、作為計算字段使用子查詢

使用子查詢的另一方法是建立計算字段。假如需要顯示

Customers

表中每個顧客的訂單總數。訂單與相應的顧客

ID

存儲在

Orders

表中。

執行這個操作,要遵循下面的步驟:

(1) 從

Customers

表中檢索顧客清單;

(2) 對于檢索出的每個顧客,統計其在

Orders

表中的訂單數目。

正如前兩課所述,可以使用

SELECT COUNT(*)

對表中的行進行計數,并且通過提供一條

WHERE

子句來過濾某個特定的顧客

ID

,僅對該顧客的訂單進行計數。

例如,下面的代碼對顧客

1000000001

的訂單進行計數:

SELECT COUNT(*) AS orders
FROM Orders
WHERE cust_id = 1000000001;
           

要對每個顧客執行

COUNT(*)

,應該将它作為一個子查詢。請看下面的代碼:

SELECT cust_name,
       cust_state,
       (SELECT COUNT(*)
        FROM Orders
        WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;
           

輸出:

cust_name                     cust_state     orders
-------------------------     ----------     ------
Fun4All                       IN             1
Fun4All                       AZ             1
Kids Place                    OH             0
The Toy Store                 IL             1
Village Toys                  MI             2
           

這條

SELECT

語句對

Customers

表中每個顧客傳回三列:

cust_name

cust_state

orders

orders

是一個計算字段,它是由圓括号中的子查詢建立的。該子查詢對檢索出的每個顧客執行一次。在此例中,該子查詢執行了 5 次,因為檢索出了 5 個顧客。

子查詢中的

WHERE

子句與前面使用的

WHERE

子句稍有不同,因為它使用了完全限定列名,而不隻是列名(

cust_id

)。它指定表名和列名(

Orders.cust_id

Customers.cust_id

)。

下面的

WHERE

子句告訴 SQL,比較

Orders

表中的

cust_id

和目前正從

Customers

表中檢索的

cust_id

WHERE Orders.cust_id = Customers.cust_id
           

用一個句點分隔表名和列名,在有可能混淆列名時必須使用這種文法。在這個例子中,有兩個

cust_id

列:一個在

Customers

中,另一個在

Orders

中。如果不采用完全限定列名,DBMS 會認為要對

Orders

表中的

cust_id

自身進行比較。因為

SELECT COUNT(*) FROM Orders WHERE cust_id = cust_id
           

總是傳回

Orders

表中訂單的總數,而這個結果不是我們想要的:

SELECT cust_name,
       cust_state,
       (SELECT COUNT(*)
        FROM Orders
        WHERE cust_id = cust_id) AS orders
FROM Customers
ORDER BY cust_name;
           

輸出:

cust_name                     cust_state     orders
-------------------------     ----------     ------
Fun4All                       IN             5
Fun4All                       AZ             5
Kids Place                    OH             5
The Toy Store                 IL             5
Village Toys                  MI             5
           

雖然子查詢在構造這種

SELECT

語句時極有用,但必須注意限制有歧義的列。

注意:完全限定列名

你已經看到了為什麼要使用完全限定列名,沒有具體指定就會傳回錯誤結果,因為 DBMS 會誤解你的意思。

有時候,由于出現沖突列名而導緻的歧義性,會引起 DBMS 抛出錯誤資訊。

例如,

WHERE

ORDER BY

子句指定的某個列名可能會出現在多個表中。

好的做法是,如果在

SELECT

語句中操作多個表,就應使用完全限定列名來避免歧義。

提示:不止一種解決方案

正如本文前面所述,雖然這裡給出的樣例代碼運作良好,但它并不是解決這種資料檢索的最有效方法。在 如何使用 SQL INNER JOIN 聯結兩個或多個表 和 SQL 如何使用自聯結、自然聯結和外聯結 學習 JOIN 時,我們還會遇到這個例子。

四、小結

本文介紹了什麼是子查詢,如何使用它們。子查詢常用于

WHERE

子句的

IN

操作符中,以及用來填充計算列。我們舉了這兩種操作類型的例子。

原文連結:https://www.developerastrid.com/sql/sql-subqueries/

(完)

sql