MySQL 子查詢(一)

  源自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

  • 容許結構化的查詢,以即可以隔離語句的每一個部分;
  •  能夠替代複雜的鏈接和聯合;
  • 相比鏈接和聯合,有更高的可讀性。實際上,正是子查詢這個創新給了人們靈感把SQL叫作結構化查詢語言。

  

  子查詢的語法要點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);
相關文章
相關標籤/搜索