源自MySQL 5.7 官方手冊 13.2.10 Subquery Syntaxhtml
〇、MySQL子查詢介紹mysql
子查詢指的是嵌套在某個語句中的SELECT語句。sql
MySQL支持標準SQL所要求的全部子查詢形式和操做,此外還進行了一些擴展。函數
下面就是一個有子查詢的示例:性能
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
在此示例中,SELECT * FROM t1 ...是外部查詢(或外部語句),而(SELECT column1 FROM t2)是子查詢。子查詢嵌套在外部查詢中,實際上能夠將子查詢嵌套在其餘子查詢中,達到至關深的程度。子查詢必須始終出如今括號內。優化
子查詢的優勢:spa
子查詢的語法要點scala
下面是一個示例語句,顯示了SQL標準指定的並在MySQL中支持的子查詢語法的要點:code
DELETE FROM t1 WHERE s11 > ANY (SELECT COUNT(*) /* no hint */ FROM t2 WHERE NOT EXISTS (SELECT * FROM t3 WHERE ROW(5*t2.s1,77)= (SELECT 50,11*s1 FROM t4 UNION SELECT 50,77 FROM (SELECT * FROM t5) AS t5)));
一個子查詢能夠返回一個標量(單個值),單個行,單個列或一個表(一個或多個列的一行或多行)。他們分別叫作標量子查詢、列子查詢、行子查詢以及表子查詢。htm
返回特定類型結果的子查詢一般只能在某些上下文中使用,接下來的章節會闡述。
子查詢能夠應用在大部分語句中,MySQL對此限制不多。
子查詢能夠包含不少普通SELECT語句中的關鍵字:DISTINCT, GROUP BY, ORDER BY, LIMIT, joins, index hints, UNION constructs, comments, functions等。
一個子查詢的外接語句能夠爲:SELECT, INSERT, UPDATE, DELETE, SET, or DO。
可是在MySQL中,不能在修改一個表的同時在子查詢中對同一個表進行SELECT操做。這適用於DELETE,INSERT,REPLACE,UPDATE等語句,還有LOAD DATA((由於子查詢能夠在SET子句中使用))。
關於優化器怎麼處理子查詢的知識,see Section 8.2.2,「Optimizing Subqueries, Derived Tables, and View References」。
有關子查詢使用限制的討論,包括某些形式的子查詢語法的性能問題,see Section C.4, 「Restrictions on Subqueries」。
1、將子查詢做爲標量操做數
在此查詢最簡單的形式中,子查詢是一個返回單個值的標量子查詢(a scalar subquery)。標量子查詢是一個簡單的操做數,您幾乎能夠在將它使用在任何單個列值或字面值合法的地方。你能夠指望它具備通常操做數都擁有的特徵:數據類型,長度,能夠爲NULL的指示,等等。
示例:
CREATE TABLE t1 (s1 INT, s2 CHAR(5) NOT NULL); INSERT INTO t1 VALUES(100, 'abcde');
SELECT (SELECT s2 FROM t1);
這個查詢中的子查詢返回單個值——「abcde」,數據類型爲CHAR,長度爲5,字符集和排序規則等於CREATE TABLE時生效的默認值,以及一個關於該列值能夠爲NULL的提示。
若是子查詢的結果爲空集,那麼單值子查詢所取回的值的NULL性並不會直接被複制,由於此時子查詢的結果就爲NULL。如上面的子查詢,若是t1爲空表,那麼子查詢的結果將爲NULL,即便表t1中的S2列含有NOT NULL約束。
不多有一個標量子查詢不能被使用的狀況。若是一個語句只容許一個字面量值,那此時你沒法使用一個子查詢。例如,LIMIT要求整數類型的字面值參數,LOAD DATA要求一個表明文件路徑的字面量的字符串值。此時你就不能使用子查詢來提供這些值。
當你在接下來章節的示例中看到至關簡潔的子查詢時,能夠聯想下在本身的代碼中的子查詢使用更加多樣化和複雜的構造。
假設如今有兩個表:
CREATE TABLE t1 (s1 INT); INSERT INTO t1 VALUES (1); CREATE TABLE t2 (s1 INT); INSERT INTO t2 VALUES (2);
而後之心一個SELECT:
SELECT (SELECT s1 FROM t2) FROM t1; +---------------------+ | (SELECT s1 FROM t2) | +---------------------+ | 2 | +---------------------+ 1 row in set (0.00 sec)
結果爲2,由於在表t2中有一行數據,s1列值爲2。
標量子查詢能夠是表達式的一部分,但記得加括號,即便子查詢只是做爲操做數爲函數提供參數。
SELECT UPPER((SELECT s1 FROM t1)) FROM t2; +----------------------------+ | UPPER((SELECT s1 FROM t1)) | +----------------------------+ | 1 | +----------------------------+ 1 row in set (0.01 sec)
2、使用子查詢進行比較
子查詢最多見的用法是:
non_subquery_operand comparison_operator (subquery)
compare_operator是如下運算符之一:
= > < >= <= <> != <=>
例如:
... WHERE 'a' = (SELECT column1 FROM t1)
MySQL也容許這種結構:
non_subquery_operand LIKE (subquery)
在曾經某個時間,子查詢的惟一合法位置是在比較的右側,您可能仍然會發現一些堅持這一點的舊DBMS。
下面是一個常見形式子查詢比較的示例,您沒法對鏈接執行此操做。它找到表t1中column1值等於表t2中最大值的全部行:
SELECT * FROM t1 WHERE column1 = (SELECT MAX(column2) FROM t2);
這是另外一個例子,鏈接也是不可行的,由於它涉及聚合其中一個表。它查找表t1中的全部行,其中包含在給定列中出現兩次的值:
SELECT * FROM t1 AS t WHERE 2 = (SELECT COUNT(*) FROM t1 WHERE t1.id = t.id);
如果爲了將子查詢與標量進行比較,子查詢必須返回標量。
如果爲了將子查詢與行構造函數進行比較,子查詢必須是行子查詢,該子查詢返回與行構造函數具備相同數量值的行。See Section 13.2.10.5, 「Row Subqueries」.
3、帶有ANY,IN或SOME的子查詢
語法:
operand comparison_operator ANY (subquery) operand IN (subquery) operand comparison_operator SOME (subquery)
compare_operator是如下運算符之一:
= > < >= <= <> !=
ANY關鍵字,必須緊跟比較運算符後,意味着「若是操做數與子查詢中多返回的列中的任意值的比較爲TRUE,那就返回TRUE」。例如:
SELECT s1 FROM t1 WHERE s1 > ANY (SELECT s1 FROM t2);
假設表t1中有一行包含(10)。若是表t2包含(21,14,7),則表達式爲TRUE,由於t2中的值7小於10。
若是表t2包含(20,10),或者表t2爲空,則表達式爲FALSE。
若是表t2包含(NULL,NULL,NULL),則表達式結果是未知的(即NULL)。
與子查詢一塊兒使用時,單詞IN是= ANY的別名。所以,這兩個陳述是相同的:
SELECT s1 FROM t1 WHERE s1 = ANY (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 IN (SELECT s1 FROM t2);
與表達式列表一塊兒使用時,IN和= ANY不是同義詞。 IN能夠採用表達式列表,可是= ANY不能。See Section 12.3.2, 「Comparison Functions and Operators」.
NOT IN不是<> ANY的別名,而是<> ALL的別名。See Section 13.2.10.4, 「Subqueries with ALL」.
SOME這個詞是ANY的別名。所以,這兩個陳述是相同的:
SELECT s1 FROM t1 WHERE s1 <> ANY (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 <> SOME (SELECT s1 FROM t2);
SOME這個詞不多用到,可是這個例子說明了爲何它可能有用。
對於大多數人來講,英語短語「a is not equal to any b」意味着「沒有b等於a」。但這不是SQL語法的含義。在SQL中,該短語意味着「有一些b與a不相等。」使用<> SOME有助於確保每一個人都理解查詢的真正含義。
4、帶有ALL的子查詢
operand comparison_operator ALL (subquery)
ALL關鍵字必須緊跟在比較操做符後,意思是「只有操做數與子查詢返回的列中的全部值進行比較都爲true,則這個比較表達式也返回true」。例如:
SELECT s1 FROM t1 WHERE s1 > ALL (SELECT s1 FROM t2);
假設表t1中有一行包含(10)。若是表t2包含(-5,0,+ 5),則表達式爲TRUE,由於10大於t2中的全部三個值。若是表t2包含(12,6,NULL,-100),則表達式爲FALSE,由於表t2中的單個值12大於10。若是表t2包含(0,NULL,1),則表達式是未知的(即NULL)。
而若是表t2爲空,則表達式爲TRUE。所以,當表t2爲空時,如下表達式爲TRUE:
SELECT * FROM t1 WHERE 1 > ALL (SELECT s1 FROM t2);
可是當表t2爲空時,如下表達式爲NULL:
SELECT * FROM t1 WHERE 1 > (SELECT s1 FROM t2);
此外,當表t2爲空時,如下表達式爲NULL:
SELECT * FROM t1 WHERE 1 > ALL (SELECT MAX(s1) FROM t2);
一般,包含NULL值和空表的表是「邊緣狀況」。
因此在編寫子查詢時,請始終考慮是否考慮了這兩種可能性。
NOT IN是<> ALL的別名。所以,這兩個陳述是相同的:
SELECT s1 FROM t1 WHERE s1 <> ALL (SELECT s1 FROM t2); SELECT s1 FROM t1 WHERE s1 NOT IN (SELECT s1 FROM t2);