13.2.10.12 子查询限制
- 通常,您不能修改 table 并在子查询中从同一 table 中选择。例如,此限制适用于以下形式的语句:
DELETE FROM t WHERE ... (SELECT ... FROM t ...);
UPDATE t ... WHERE col = (SELECT ... FROM t ...);
{INSERT|REPLACE} INTO t (SELECT ... FROM t ...);
exception:如果对修改后的 table 使用的是派生 table,并且该派生 table 已实现而不是合并到外部查询中,则上述禁止条件不适用。 (请参见第 8.2.2.4 节“通过合并或实现来优化派生 table 和视图引用”。)示例:
UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS dt ...);
在这里,派生 table 的结果被实现为临时 table,因此在更新到t
时,已经选择了t
中的相关行。
-
仅部分支持行比较操作:
-
对于
expr [NOT] IN subquery
,*expr
可以是n
* -tuple(使用行构造函数语法指定),并且子查询可以返回*n
* -tuples 的行。因此,允许的语法更具体地 table 示为row_constructor [NOT] IN table_subquery
- 对于
expr op {ALL|ANY|SOME} subquery
,*expr
*必须是标量值,子查询必须是列子查询;它不能返回多列行。
- 对于
换句话说,对于返回* n
* -tuples 行的子查询,支持以下操作:
(expr_1, ..., expr_n) [NOT] IN table_subquery
但这不支持:
(expr_1, ..., expr_n) op {ALL|ANY|SOME} subquery
支持IN
而不支持其他IN
的行比较的原因是,通过将IN
重写为=比较和AND操作的序列来实现。此方法不能用于ALL
,ANY
或SOME
。
-
FROM
子句中的子查询不能为相关子查询。它们在查询执行期间整体实现(评估为生成结果集),因此无法对外部查询的每一行进行评估。优化程序将延迟实现,直到需要结果为止,这可以避免实现。参见第 8.2.2.4 节“通过合并或实现来优化派生 table 和视图引用”。 -
对于某些子查询运算符,MySQL 在子查询中不支持
LIMIT
:
mysql> SELECT * FROM t1
WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1);
ERROR 1235 (42000): This version of MySQL doesn't yet support
'LIMIT & IN/ALL/ANY/SOME subquery'
- MySQL 允许子查询引用具有数据修改副作用(例如在 table 中插入行)的存储函数。例如,如果
f()
插入行,则以下查询可以修改数据:
SELECT ... WHERE x IN (SELECT f() ...);
此行为是对 SQL 标准的扩展。在 MySQL 中,它会产生不确定的结果,因为根据优化器选择的处理方式,对于给定查询的不同执行,f()
可能执行不同的次数。
对于基于语句或混合格式的复制,这种不确定性的一个含义是,这样的查询可以在主服务器及其从属服务器上产生不同的结果。