1.子查詢
前面的系列介紹的都是簡單的查詢場景,其中都只涉及到單張表的數據檢索。但是在日常是實際應用中,數據模型之間的關系都非常的復雜,數據的需求一般都是來源於多個數據模型之間的組合而成,即對應多張表的數據關聯。
對應以上場景,在SQL中一般有三種實現的方式:
- 使用多個單條SQL,按邏輯步驟檢索,將其中的一條檢索結果作為下一條檢索的條件;
- 使用子查詢,即將多個單挑SQL利用相應的邏輯關鍵字合並,子查詢是DBMS所支持;
- 使用表聯結的方式,即join;
本章就簡單的回顧下SQL中的子查詢,從上面的總結中可以看出,子查詢其實利用模型之間的關系將單條SQL合並成一條復雜的SQL。那么如果要寫出這樣的復雜子查詢的SQL,首先需要梳理清楚需求中的數據模型之間的關系,根據需求的結果區分出查詢主體,查詢的關聯關系體,然后再分成單步驟的SQL,最后將其合並即可;
下面看個例子:
有三個實體,對應三張表:
- 顧客表
- 商品表
- 訂單表
訂單中含有商品id,顧客id。現在需求:查詢購買商品x1的所有顧客。
-
分析:最終的結果是要查詢出顧客,所以查詢柱體是顧客,即外查詢是顧客。但是查詢顧客的條件是,購買了x1商品的顧客,所以需要查出購買了x1商品的顧客id,然后根據顧客id查詢顧客,所以子查詢是根據商品id x1查詢。
-
步驟:
-
在表orders中查詢x1商品的顧客id: select cus_id from orders where mer_id = 'x1';
-
根據上述的查詢結果作為條件,查詢顧客:select * from customers where cus_id = 'xxxx';
最后將根據需求結果和實體的關聯關系合並SQL:
select * from customers where customers.cus_id in (select cus_id from orders where mer_id = 'x1');
其實SQL中子查詢有兩種應用方式:
- 第一種也就上面的最常使用到的場景,將子查詢的結果作為外查詢的條件,即子查詢屬於外查詢where子句的一部分
- 第二種常用是將子查詢統計結果作為外查詢的列
比如需求:統計每個顧客購訂單數量。
-
分析:顧客仍然是主體,所以外查詢是查顧客表。但是執行的邏輯剛好和上述例子相反,上述是以商品id為條件查詢顧客。這里是查詢顧客以及其訂單數,但是訂單數的統計是從顧客這一維度出發,所以需要根據顧客查詢訂單數。
-
步驟:
- 先查詢出所有顧客: select * from customers;
- 再根據顧客去統計每個顧客的訂單數: select count(*) from orders where orders.cus_id = 'xxxxx';
最后組合SQL:
select cus_id, cus_name, (select count(*) from orders where orders.cus_id = customers.cus_id) from customers;
以上例子是子查詢的第二種用法。
2.總結
上述總結的子查詢的兩種方式:
- 要么是根據子查詢的邏輯結果作為外查詢的查詢條件(子查詢在where子句中)
- 要么是根據外查詢的結果作為子查詢的條件(子查詢在select子句中)
SQL中沒有限制子查詢的數量,但是一般實際應用中子查詢的不宜使用過多:
- 使用子查詢必然會導致SQL更為復雜,SQL表述的語義較為難以理解,可閱讀性變差
- 子查詢使用過多,會嚴重消耗性能
- 子查詢不利於SQL的調試,問題的排查