MySQL 子查詢(二)

  接上篇文章,從這節起:MySQL 5.7 13.2.10.5 Row Subquerieshtml

 

5、行子查詢(ROW Subqueries)mysql

  標量子查詢返回單個值,列子查詢返回一個列的多個值。而行子查詢是子查詢變體,它返回單個行,所以能夠返回多個列值。sql

  可用於行子查詢比較的操做符以下:函數

=  >  <  >=  <=  <>  !=  <=>

  如下是兩個示例:性能

SELECT * FROM t1
  WHERE (col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);

SELECT * FROM t1
  WHERE ROW(col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);

  對於這兩個查詢,若是t2表中有一個id=10的行(僅有一個),則子查詢返回這單個行。若是這行數據中的col三、col4兩個列的列值與t1表中的任何行的col一、col2相等,則WHERE表達式返回TRUE。兩個查詢都t1表中的這些行。優化

  若是t2行col3和col4值不等於任何t1行的col1和col2值,則WHERE表達式爲FALSE且查詢返回空結果集。spa

  若是子查詢不生成行(空的結果集),則表達式是未知的(即NULL)。若是子查詢產生多行,則會發生錯誤,由於一個行子查詢最多隻能返回一行code

  有關每一個運算符如何進行行比較的信息,see Section 12.3.2, 「Comparison Functions and Operators」.htm

  

  表達式(1,2)和ROW(1,2)有時被稱爲行構造器。二者是等價的。行構造函數和行子查詢返回的行必須包含相同數量的值。blog

  行構造函數用於與返回兩列或更多列的子查詢進行比較(只返回一行數據)。當子查詢返回單個列時,這被視爲標量值而不是行,所以行構造函數不能與不返回至少兩列的子查詢一塊兒使用。

  所以如下查詢會失敗並出現語法錯誤:

SELECT * FROM t1 WHERE ROW(1) = (SELECT column1 FROM t2)

  行構造函數在其餘上下文中是合法的。例如,如下兩個語句在語義上是等效的(而且由優化器以相同的方式處理):

SELECT * FROM t1 WHERE (column1,column2) = (1,1);
SELECT * FROM t1 WHERE column1 = 1 AND column2 = 1;

  如下查詢回答請求,「查找表t1中也存在於表t2中的全部行」

SELECT column1,column2,column3
  FROM t1
  WHERE (column1,column2,column3) IN
         (SELECT column1,column2,column3 FROM t2);

  關於優化器和行構造器的更多信息,see Section 8.2.1.19, 「Row Constructor Expression Optimization」。

 

6、具備EXISTS或NOT EXISTS的子查詢

  If a subquery returns any rows at all, EXISTS subquery is TRUE, and NOT EXISTS subquery is FALSE.(若是一個子查詢返回任何行,那麼「EXISTS subquery 會返回TRUE,NOT EXISTS subquery返回FALSE」)

  以下:

SELECT column1 FROM t1 WHERE EXISTS (SELECT * FROM t2);

  傳統上,EXISTS子查詢以SELECT *開頭,但它能夠從SELECT 5或SELECT column1開始,或者任何東西。由於MySQL忽略了這樣一個子查詢中的SELECT列表,因此沒有區別。

  以前的例子中,若是t2表中有任何數據行,哪怕是全爲NULL值的一行數據,那麼EXISTS條件判斷也會爲TRUE。這其實是一個不太可能出現的例子,由於[NOT] EXISTS子查詢幾乎老是包含相關性。下面列出了更現實的例子:

  一、一個或多個城市有哪一種類型的商店(找出在stores表和cities_stores都存在的
store_type)

SELECT DISTINCT store_type FROM stores
  WHERE EXISTS (SELECT * FROM cities_stores
                WHERE cities_stores.store_type = stores.store_type);

  二、全部的城市都沒有的商店類型是哪一種?(找出在stores表和cities_stores都不存在的
store_type)

SELECT DISTINCT store_type FROM stores
  WHERE NOT EXISTS (SELECT * FROM cities_stores
                    WHERE cities_stores.store_type = stores.store_type);

  三、全部城市都有的商店類型是哪一種?

SELECT DISTINCT store_type FROM stores s1
  WHERE NOT EXISTS (
    SELECT * FROM cities WHERE NOT EXISTS (
      SELECT * FROM cities_stores
       WHERE cities_stores.city = cities.city
       AND cities_stores.store_type = stores.store_type));

  最後一個示例是雙嵌套的NOT EXISTS查詢。也就是說,它在NOT EXISTS子句中還有一個NOT EXISTS子句。在形式上,它回答了這樣一個問題——一個城市是否存在在Stores表中不存在的商店?更簡單的說法是:嵌套的NOT EXISTS回答了這樣的問題——「is x TRUE for all y?」

 

7、相關子查詢(Correlated Subqueries)

  相關子查詢是這樣一個子查詢——在子查詢中引用外接查詢中的表。

  以下所示:

SELECT * FROM t1
  WHERE column1 = ANY (SELECT column1 FROM t2
                       WHERE t2.column2 = t1.column2);

  請注意,子查詢包含對t1表中列的引用,即便子查詢的FROM子句未說起表t1。MySQL會在子查詢外部查找t1。

  假設t1表有這樣一個行:column1=5,column2=6;

  同時,t2表包含這樣一個行:column1=5,column2=7;

  此時,WHERE表達式「WHERE column1 = ANY(SELECT column1 FROM t2)」會返回TRUE。但在上面的例子中,子查詢中的WHERE子句爲FALSE,因此整個子句返回空集,而外部的WHERE表達式總爲FALSE。

 

  範圍規則:MySQL會從內到外對語句進行評估。

SELECT column1 FROM t1 AS x
  WHERE x.column1 = (SELECT column1 FROM t2 AS x
    WHERE x.column1 = (SELECT column1 FROM t3
      WHERE x.column2 = t3.column1));

  在這個語句中,x.column2必須是表t2中的一列,由於SELECT column1 FROM t2 AS x ...重命名t2。它不是表t1中的列,由於SELECT column1 FROM t1 ...是一個更遠的外部查詢。

  對於HAVING或ORDER BY子句中的子查詢,MySQL還會在外部的SELECT列表中查找列名。

  

  在某些狀況下,相關子查詢會被優化掉。例如:

val IN (SELECT key_val FROM tbl_name WHERE correlated_condition)

  不然,它們效率低下而且可能很慢。將查詢重寫爲鏈接可能會提升性能。

  

  相關子查詢中的聚合函數可能包含外部引用,前提是該函數只包含外部引用,而且該函數不包含在另外一個函數或表達式中。

相關文章
相關標籤/搜索