接上篇文章,从这节起: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)
不然,它们效率低下而且可能很慢。将查询重写为链接可能会提升性能。
相关子查询中的聚合函数可能包含外部引用,前提是该函数只包含外部引用,而且该函数不包含在另外一个函数或表达式中。