mysql 子查询
接上篇文章,從這節起:MySQL 5.7?13.2.10.5?Row Subqueries
?
五、行子查詢(ROW Subqueries)
標量子查詢返回單個值,列子查詢返回一個列的多個值。而行子查詢是子查詢變體,它返回單個行,因此可以返回多個列值。
可用于行子查詢比較的操作符如下:
= > < >= <= <> != <=>以下是兩個示例:
SELECT * FROM t1WHERE (col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);SELECT * FROM t1WHERE ROW(col1,col2) = (SELECT col3, col4 FROM t2 WHERE id = 10);對于這兩個查詢,如果t2表中有一個id=10的行(僅有一個),則子查詢返回這單個行。如果這行數據中的col3、col4兩個列的列值與t1表中的任何行的col1、col2相等,則WHERE表達式返回TRUE。兩個查詢都t1表中的這些行。
如果t2行col3和col4值不等于任何t1行的col1和col2值,則WHERE表達式為FALSE且查詢返回空結果集。
如果子查詢不生成行(空的結果集),則表達式是未知的(即NULL)。如果子查詢產生多行,則會發生錯誤,因為一個行子查詢最多只能返回一行。
有關每個運算符如何進行行比較的信息,see Section?12.3.2, “Comparison Functions and Operators”.
表達式(1,2)和ROW(1,2)有時被稱為行構造器。兩者是等價的。行構造函數和行子查詢返回的行必須包含相同數量的值。
行構造函數用于與返回兩列或更多列的子查詢進行比較(只返回一行數據)。當子查詢返回單個列時,這被視為標量值而不是行,因此行構造函數不能與不返回至少兩列的子查詢一起使用。
因此以下查詢會失敗并出現語法錯誤:
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,column3FROM t1WHERE (column1,column2,column3) IN(SELECT column1,column2,column3 FROM t2);關于優化器和行構造器的更多信息,see Section?8.2.1.19, “Row Constructor Expression Optimization”。
?
六、具有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子查詢幾乎總是包含相關性。下面列出了更現實的例子:
1、一個或多個城市有哪種類型的商店(找出在stores表和cities_stores都存在的
store_type)
2、所有的城市都沒有的商店類型是哪種?(找出在stores表和cities_stores都不存在的
store_type)
3、所有城市都有的商店類型是哪種?
SELECT DISTINCT store_type FROM stores s1WHERE NOT EXISTS (SELECT * FROM cities WHERE NOT EXISTS (SELECT * FROM cities_storesWHERE cities_stores.city = cities.cityAND cities_stores.store_type = stores.store_type));最后一個示例是雙嵌套的NOT EXISTS查詢。也就是說,它在NOT EXISTS子句中還有一個NOT EXISTS子句。在形式上,它回答了這樣一個問題——一個城市是否存在在Stores表中不存在的商店?更簡單的說法是:嵌套的NOT EXISTS回答了這樣的問題——“is x TRUE for all y?”
?
七、相關子查詢(Correlated Subqueries)
相關子查詢是這樣一個子查詢——在子查詢中引用外接查詢中的表。
如下所示:
SELECT * FROM t1WHERE column1 = ANY (SELECT column1 FROM t2WHERE 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 xWHERE x.column1 = (SELECT column1 FROM t2 AS xWHERE x.column1 = (SELECT column1 FROM t3WHERE 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)否則,它們效率低下并且可能很慢。將查詢重寫為連接可能會提高性能。
相關子查詢中的聚合函數可能包含外部引用,前提是該函數只包含外部引用,并且該函數不包含在另一個函數或表達式中。
總結
- 上一篇: 详细讲述MySQL中的子查询操作
- 下一篇: MySQL学习(四、子查询)