目標(biāo):
11.1 子查詢
11.2 利用子查詢進(jìn)行過(guò)濾
11.3 作為計(jì)算字段使用子查詢
11.1 子查詢
查詢(query)任何 SQL 語(yǔ)句都是查詢嘿架。但此術(shù)語(yǔ)一般指 SELECT 語(yǔ)句医男。
SQL 還允許創(chuàng)建子查詢(subquery)而柑,即嵌套在其他查詢中的查詢吠卷。
11.2 利用子查詢進(jìn)行過(guò)濾
要求:假如需要列出訂購(gòu)物品 RGAN01 的所有顧客悼潭,應(yīng)該怎樣檢索江解?下
面列出具體的步驟贤牛。
(1) 檢索包含物品 RGAN01 的所有訂單的編號(hào)构蹬。
(2) 檢索具有前一步驟列出的訂單編號(hào)的所有顧客的 ID。
(3) 檢索前一步驟返回的所有顧客 ID 的顧客信息悔据。
SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01';
SELECT cust_id
FROM Orders
WHERE order_num IN (20007,20008);
#嵌套
SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
????????????????????????????????????????FROM OrderItems
????????????????????????????????????????WHERE prod_id = 'RGAN01');
輸出:# cust_id'1000000004''1000000005'
分析:在 SELECT 語(yǔ)句中庄敛,子查詢總是從內(nèi)向外處理。
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'));
注意:只能是單列
作為子查詢的 SELECT 語(yǔ)句只能查詢單個(gè)列科汗。企圖檢索多個(gè)列將返回錯(cuò)誤藻烤。
注意:子查詢和性能
這里給出的代碼有效,并且獲得了所需的結(jié)果头滔。但是怖亭,使用子查詢并不總是執(zhí)行這類數(shù)據(jù)檢索的最有效方法。
11.3 作為計(jì)算字段使用子查詢
使用子查詢的另一方法是創(chuàng)建計(jì)算字段坤检。假如需要顯示 Customers 表中每個(gè)顧客的訂單總數(shù)兴猩。訂單與相應(yīng)的顧客 ID 存儲(chǔ)在 Orders 表中。
執(zhí)行這個(gè)操作缀蹄,要遵循下面的步驟:
(1) 從 Customers 表中檢索顧客列表峭跳;
(2) 對(duì)于檢索出的每個(gè)顧客,統(tǒng)計(jì)其在 Orders 表中的訂單數(shù)目缺前。
SELECT cust_name, cust_state,
? ? ? ? ? ? ? (SELECT COUNT(*)
? ? ? ? ? ? ?? FROM Orders
? ? ? ? ? ?? ? WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;
子查詢中的 WHERE 子句與前面使用的 WHERE 子句稍有不同蛀醉,因?yàn)樗褂昧送耆薅忻恢皇橇忻╟ust_id)衅码。它指定表名和列名(Orders.cust_id和 Customers.cust_id).
注意:完全限定列名 你已經(jīng)看到了為什么要使用完全限定列名拯刁,沒(méi)有具體指定就會(huì)返回錯(cuò)誤結(jié)果,因?yàn)?DBMS 會(huì)誤解你的意思逝段。有時(shí)候垛玻,由于出現(xiàn)沖突列名而導(dǎo)致的歧義性,會(huì)引起 DBMS 拋出錯(cuò)誤信息奶躯。例如帚桩,WHERE 或 ORDER BY 子句指定的某個(gè)列名可能會(huì)出現(xiàn)在多個(gè)表中。好的做法是嘹黔,如果在SELECT 語(yǔ)句中操作多個(gè)表账嚎,就應(yīng)使用完全限定列名來(lái)避免歧義。
11.4小結(jié)
這一課學(xué)習(xí)了什么是子查詢儡蔓,如何使用它們郭蕉。子查詢常用于 WHERE 子句的 IN 操作符中,以及用來(lái)填充計(jì)算列喂江。我們舉了這兩種操作類型的例子召锈。
-- 11.2 利用子查詢進(jìn)行過(guò)濾
SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01';
SELECT cust_id
FROM Orders
WHERE order_num IN (20007,20008);
SELECT cust_id
FROM Orders
WHERE order_num IN (SELECT order_num
FROM OrderItems
WHERE prod_id = 'RGAN01');
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'));
-- 11.3 作為計(jì)算字段使用子查詢
SELECT cust_name, cust_state,
? ? ? (SELECT COUNT(*)
? ? ? ? FROM Orders
? ? ? ? WHERE Orders.cust_id = Customers.cust_id) AS orders
FROM Customers
ORDER BY cust_name;
11.5挑戰(zhàn)題
1. 使用子查詢,返回購(gòu)買價(jià)格為 10 美元或以上產(chǎn)品的顧客列表获询。你需要使用 OrderItems 表查找匹配的訂單號(hào)(order_num)涨岁,然后使用Order 表檢索這些匹配訂單的顧客 ID(cust_id)拐袜。
SELECT cust_id,cust_name
FROM orders
WHERE order_num IN(SELECT order_num
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FROM orderitems
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? WHERE item_price>=10 );
2. 你想知道訂購(gòu) BR01 產(chǎn)品的日期。編寫 SQL 語(yǔ)句梢薪,使用子查詢來(lái)確定哪些訂單(在 OrderItems 中)購(gòu)買了 prod_id 為 BR01 的產(chǎn)品阻肿,然后從 Orders 表中返回每個(gè)產(chǎn)品對(duì)應(yīng)的顧客 ID(cust_id)和訂單日期(order_date)。按訂購(gòu)日期對(duì)結(jié)果進(jìn)行排序沮尿。
SELECT cust_id,order_date
FROM Orders
WHERE order_num IN (SELECT order_num
? ? ? ? ? ? ? ? ? ? FROM OrderItems
? ? ? ? ? ? ? ? ? ? WHERE prod_id='BR01')
order by order_date;
3. 現(xiàn)在我們讓它更具挑戰(zhàn)性。在上一個(gè)挑戰(zhàn)題较解,返回購(gòu)買 prod_id 為BR01 的產(chǎn)品的所有顧客的電子郵件(Customers 表中的 cust_email)畜疾。提示:這涉及 SELECT 語(yǔ)句,最內(nèi)層的從 OrderItems 表返回 order_num印衔,中間的從 Customers 表返回 cust_id啡捶。
SELECT cust_email,cust_name
FROM customers
WHERE cust_id IN(SELECT cust_id
? ? FROM Orders
? ? ? ? ? ? ? ? WHERE order_num IN (SELECT order_num
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? FROM OrderItems
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? WHERE prod_id='BR01'));
4. 我們需要一個(gè)顧客 ID 列表,其中包含他們已訂購(gòu)的總金額奸焙。編寫 SQL語(yǔ)句瞎暑,返回顧客 ID(Orders 表中的 cust_id),并使用子查詢返回total_ordered 以便返回每個(gè)顧客的訂單總數(shù)与帆。將結(jié)果按金額從大到小排序了赌。提示:你之前已經(jīng)使用 SUM()計(jì)算訂單總數(shù)。
SELECT cust_id,
? ? ? (SELECT SUM(item_price*quantity)
? ? ? ? FROM OrderItems
? ? ? ? WHERE Orders.order_num = OrderItems.order_num) AS total_ordered
FROM Orders
ORDER BY total_ordered DESC;
5. 再來(lái)玄糟。編寫 SQL 語(yǔ)句勿她,從 Products 表中檢索所有的產(chǎn)品名稱(prod_name),以及名為 quant_sold 的計(jì)算列阵翎,其中包含所售產(chǎn)品的總數(shù)(在 OrderItems 表上使用子查詢和 SUM(quantity)檢索)逢并。
SELECT prod_name,
? ? ? (SELECT Sum(quantity)
? ? ? ? FROM OrderItems
? ? ? ? WHERE Products.prod_id=OrderItems.prod_id) AS quant_sold
FROM Products;