SQL必知必會筆記十一(使用子查詢)

2021-10-05 12:30:17 字數 3590 閱讀 5554

select語句是sql的查詢。我們迄今為止所看到的所有select語句都是簡單查詢,即從單個資料庫表中檢索資料的單條語句。

查詢(query)

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

sql還允許建立子查詢(subquery),即巢狀在其他查詢中的查詢。

說明:mysql支援

如果使用mysql,應該知道對子查詢的支援是從4.1版本引入的。mysql的早期版本不支援子查詢。

例如:訂單儲存在兩個表中。每個訂單包含訂單編號、客戶id、訂單日期,在orders表中儲存為一行。各訂單的物品儲存在相關的orderitems表中。orders表不儲存顧客資訊,只儲存顧客id。顧客的實際資訊儲存在customers表中。

假如需要列出訂購物品rgan01的所有顧客,應該怎樣檢索?下面列出具體的步驟。

(1)檢索包含物品rgan01的所有訂單的編號。

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

(3)檢索前一步驟返回的所有顧客id的顧客資訊。

上述每個步驟都可以單獨作為乙個查詢來執行。可以把一條select語句返回的結果用於另一條select語句的where子句。

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

(1)第一條select語句的含義很明確,它對prod_id為rgan01的所有訂單物品,檢索其order_num列。輸出列出了兩個包含此物品的訂單:

select order_num from orderitems where prod_id = 'rgan01';

select cust_id from orders where orders_num in (20007,20008);

結合這兩個查詢,把第乙個查詢(返回訂單號的那乙個)變為子查詢。請看下面的select語句:

select cust_id from orders where order_num in (select order_num from orderitems where prod_id = 'rgan01');

在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子句所返回的值相同。

(3)下一步是檢索這些顧客id的顧客資訊。

select cust_name, cust_contact from customers where cust_id in ('1000000004','1000000005');

子查詢就是:

select cust_name, cust_contact from customers where cust_id in (select cust_id from order where order_num in (select order_num from orderitems where prod_id = 'rgan01')) ;

為了執行上述select語句,dbms實際上必須執行三條select語句。最裡邊的子查詢返回訂單號列表,此列表用於其外面的子查詢的where子句。外面的子查詢返回顧客id列表,此顧客id列表用於最外層查詢的where子句。最外層查詢返回所需的資料。

在where子句中使用子查詢能夠編寫出功能很強且很靈活的sql語句。對於能巢狀的子查詢的數目沒有限制,不過在實際使用時由於效能的限制,不能巢狀太多的子查詢。

注意:只能是單列

作為子查詢的select語句只能查詢單個列。企圖檢索多個列將返回錯誤。

注意:子查詢和效能

這裡給出的**有效,並且獲得了所需的結果。但是,使用子查詢並不總是執行這類資料檢索的最有效方法。

包含子查詢的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 orders where orders.cust_id = customers.cust_id) as orders from customers order by cust_name;

這條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:

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;

雖然子查詢在構造這種select語句時極有用,但必須注意限制有歧義的列。

注意:完全限定列名

沒有具體指定就會返回錯誤結果,因為dbms會誤解你的意思。有時候,由於出現衝突列名而導致的歧義性,會引起dbms丟擲錯誤資訊。

例如,where或order by子句指定的某個列名可能會出現在多個表中。好的做法是,如果在select語句中操作多個表,就應使用完全限定列名來避免歧義。

雖然這裡給出的樣例**執行良好,但它並不是解決這種資料檢索的最有效方法。

SQL必知必會 筆記 子查詢 IN

查詢 query 任何sql語句都是查詢。但此術語一般指select 語句。子查詢 subquery 即巢狀在其他查詢中的查詢,也可以說,巢狀在其他select語句中的select語句。舉個例子,我們想知道購買tnt2產品的客戶的id,但是產品id和客戶id不在同一張表上,兩張表的訂單號碼這一列是相...

MySQL必知必會 十一 使用子查詢

開始線 查詢 任何sql語句都是查詢。但此術語一般指select語句 列出訂購物品tnt2的所有客戶 1.檢索包含物品tnt2的所有訂單的編號 2.檢索具有前一步列出的訂單編號的所有客戶的id 3.檢索前一步返回的所有客戶id的客戶資訊 現在得到訂購tnt2的所有客戶的id,下一步是檢索這些客戶id...

SQL 必知必會 筆記 9 使用子查詢

子查詢 subquery 即巢狀在其他查詢中的查詢。select 語句中,子查詢總是從內向外處理。示例 1 select cust name,cust contact 2from customers 3where cust id in select cust id 4from order 5wher...