使用子查詢進行過濾
SELECT語句用於SQL中的查詢。之前使用的所有SELECT語句都是簡單查詢,即從單個數據庫表中檢索數據的單個語句。但是,SQL也可以創建子查詢,即嵌套在其他查詢中的查詢。
示例:
數據表:這次使用的數據庫表都是關系表。訂單存儲在兩個表中。每個訂單都包含訂單號、客戶ID和訂單日期,並作為壹行存儲在Orders表中。每個訂單的項目都存儲在相關的OrderItems表中。Orders表不存儲客戶信息,只存儲客戶ID。實際的客戶信息存儲在Customers表中。
如果現在需要檢索所有訂購RGAN01的客戶,應該如何檢索?步驟如下:
①檢索包含RGAN01項目的所有訂單的編號。
②檢索上壹步中列出的訂單號的所有客戶的id。
③檢索上壹步返回的所有客戶id的客戶信息。
上述每個步驟都可以作為壹個查詢獨立執行。
可以將壹個SELECT語句返回的結果用於另壹個SELECT語句的WHERE子句,也可以使用子查詢將三個查詢合並到壹個語句中。
①第壹條語句的含義很清楚,即對於所有prod_id為RGAN01的訂單項,檢索order_num列。
分析:通過這個語句,我們知道哪個訂單包含要檢索的項目。
②接下來,查詢與從上述語句中檢索到的訂單20007和20008相關的客戶ID。這裏可以使用IN子句。
可以將下面兩個查詢組合起來,將第壹個查詢變成壹個子查詢。
分析:在SELECT語句中,子查詢總是由內向外處理。在處理上述SELECT語句時,DBMS實際上執行兩個操作。
首先,執行括號()中的查詢,該查詢返回兩個訂單號:20007和20008。
然後,這兩個值以IN運算符要求的逗號分隔格式傳遞給外部查詢的WHERE子句。外部查詢變成:
該語句檢索的結果與前面硬編碼的WHERE子句返回的結果相同。
③訂購產品RGAN01的所有客戶id均從上述語句中獲得:100004和100005。接下來,檢索這些客戶id的客戶信息。
還可以將WHERE子句轉換成子查詢,這樣就不必對這些客戶id進行硬編碼。
分析:DBMS實際上要執行三條SELECT語句才能完成上述語句。最裏面的子查詢返回序號,該序號用在外部子查詢的WHERE子句中。外部子查詢返回客戶ID列,該列用在最外層查詢的WHERE子句中。最外層的查詢返回最終所需的數據。
可以看出,在WHERE子句中使用子查詢可以寫出強大靈活的SQL語句。可以嵌套的子查詢數量沒有限制,但在實際應用中,由於性能限制,不宜嵌套過多的子查詢。
註意:作為子查詢的SELECT語句只能查詢壹列,檢索多列將返回錯誤。此外,使用子查詢並不總是執行這種數據檢索的最有效方式。
將子查詢用作計算字段
使用子查詢的另壹種方法是創建計算字段。
示例:您需要顯示Customers表中每個客戶的訂單總數。訂單和相應的客戶id存儲在Orders表中。為此,您需要以下步驟:
①從客戶表中檢索客戶列表。
②對於檢索到的每個客戶,統計Orders表中的訂單數。
在這裏,我們可以使用前面介紹的SELECT COUNT(*)對表中的行進行計數,並通過WHERE子句篩選特定的客戶ID,只對該客戶的訂單進行計數。
統計客戶100001的訂單如下:
要對每個客戶執行COUNT(*),需要將其用作子查詢,如下所示:
分析:該SELECT語句為Customers表中的每個客戶返回三列:cust_name、cust_state和orders。Orders是壹個計算字段,由括號中的子查詢建立。該子查詢針對檢索到的每個客戶執行壹次。在本例中,子查詢執行了五次,因為檢索了五個客戶。
子查詢中的WHERE子句與前面的WHERE子句略有不同,因為它使用完全限定的列名,而不僅僅是列名(cust_id)。它指定表名和列名(Orders.cust_id和Customers.cust_id)。下面的WHERE子句告訴SQL將Orders表中的cust_id與當前從Customers表中檢索的cust_id進行比較:
當列名容易混淆時,必須用句點將表名和列名分開。在這個例子中,有兩個cust_id列:壹個在Customers中,另壹個在Orders中。如果沒有完全限定名,DBMS會認為應該比較Orders表中的cust_id本身。因為:
上面的語句總是返回Orders表中的訂單總數,這不是我們想要的,如下所示:
從上面可以看出,在構造語句時,如果涉及多個表,並且沒有區分相同的列名,DBMS就會拋出錯誤信息。
在SELECT語句中操作多個表時,使用完全限定的列名來避免歧義是壹個很好的做法。
最後,總結子查詢的特點:
①子查詢必須用括號括起來。
②子查詢的SELECT子句中只能有壹列,除非主查詢中有多列,用於與子查詢選擇的列進行比較。
③子查詢不能使用ORDER BY,但主查詢可以。在子查詢中,GROUP BY可以起到與ORDER BY相同的作用。
④返回多行數據的子查詢只能用於多值運算符,如IN運算符。
⑤選擇列表不能包含對BLOB、ARRAY、CLOB或NCLOB類型值的任何引用。
⑥子查詢不能直接用於聚合函數。
⑦ BETWEEN運算符不能用於子查詢,但可以用於子查詢。
這個介紹就到此為止。下壹篇文章將解釋連接和高級連接的使用。
下次見!