SQL 子查询
??查詢(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。利用第5課介紹的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實際上執行了兩個操作。 首先,它執行下面的查詢: SELECT order_num FROM orderitems WHERE prod_id='RGAN01' 此查詢返回兩個訂單號:20007和20008。然后,這兩個值以IN操作符要求的逗號分隔的格式傳遞給外部查詢的WHERE子句。外部查詢變成: SELECT cust_id FROM orders WHERE order_num IN (20007,20008) 可以看到,輸出是正確的,與前面硬編碼WHERE子句所返回的值相同。 提示:格式化SQL 包含子查詢的SELECT語句難以閱讀和調試,它們在較為復雜時更是如此。如上所示,把子查詢分解為多行并進行適當的縮進,能極大地簡化子查詢的使用。 現在得到了訂購物品RGA N01的所有顧客的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_idFROM OrderWHERE order_num IN (SELECT order_numFROM OrderItemsWHERE 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語句只能查詢單個列。企圖檢索多個列將返回錯誤。 警告:子查詢和性能 這里給出的代碼有效,并且獲得了所需的結果。但是,使用子查詢并不總是執行這類數據檢索的最有效方法。
作為計算字段使用子查詢 使用子查詢的另一方法是創建計算字段。假如需要顯示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 OrdersWHERE 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 OrdersWHERE 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語句時極有用,但必須注意限制有歧義的列。
利用子查詢進行過濾 訂單存儲在兩個表中。每個訂單包含訂單編號、客戶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。利用第5課介紹的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實際上執行了兩個操作。 首先,它執行下面的查詢: SELECT order_num FROM orderitems WHERE prod_id='RGAN01' 此查詢返回兩個訂單號:20007和20008。然后,這兩個值以IN操作符要求的逗號分隔的格式傳遞給外部查詢的WHERE子句。外部查詢變成: SELECT cust_id FROM orders WHERE order_num IN (20007,20008) 可以看到,輸出是正確的,與前面硬編碼WHERE子句所返回的值相同。 提示:格式化SQL 包含子查詢的SELECT語句難以閱讀和調試,它們在較為復雜時更是如此。如上所示,把子查詢分解為多行并進行適當的縮進,能極大地簡化子查詢的使用。 現在得到了訂購物品RGA N01的所有顧客的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_idFROM OrderWHERE order_num IN (SELECT order_numFROM OrderItemsWHERE 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語句只能查詢單個列。企圖檢索多個列將返回錯誤。 警告:子查詢和性能 這里給出的代碼有效,并且獲得了所需的結果。但是,使用子查詢并不總是執行這類數據檢索的最有效方法。
作為計算字段使用子查詢 使用子查詢的另一方法是創建計算字段。假如需要顯示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 OrdersWHERE 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 OrdersWHERE 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語句時極有用,但必須注意限制有歧義的列。
總結
- 上一篇: linux 安装pkg文件,pkgfil
- 下一篇: linux cmake编译源码,linu