通常,您不能在子查询中修改表并从同一表中选择数据。例如,此限制适用于以下形式的语句
DELETE FROM t WHERE ... (SELECT ... FROM t ...); UPDATE t ... WHERE col = (SELECT ... FROM t ...); {INSERT|REPLACE} INTO t (SELECT ... FROM t ...);
例外:如果对修改的表使用派生表,并且该派生表被物化而不是合并到外部查询中,则上述禁止不适用。(参见 第 10.2.2.4 节,“通过合并或物化优化派生表、视图引用和公共表表达式”。)示例
UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS dt ...);
此处,派生表的结果被物化为一个临时表,因此在对
t
进行更新时,t
中的相关行已选择。通常,您可以通过添加
NO_MERGE
优化提示来影响优化器以物化派生表。参见 第 10.9.3 节,“优化提示”。行比较操作仅部分支持
对于
,expr
[NOT] INsubquery
expr
可以是一个n
元组(使用行构造语法指定),子查询可以返回n
元组的行。因此,允许的语法更具体地表示为row_constructor
[NOT] INtable_subquery
对于
,expr
op
{ALL|ANY|SOME}subquery
expr
必须是标量值,子查询必须是列子查询;它不能返回多列行。
换句话说,对于返回
n
元组行的子查询,这是支持的(expr_1, ..., expr_n) [NOT] IN table_subquery
但是,这是不支持的
(expr_1, ..., expr_n) op {ALL|ANY|SOME} subquery
支持
IN
的行比较而不支持其他比较的原因是,IN
是通过将其重写为一系列=
比较和AND
操作来实现的。这种方法不能用于ALL
、ANY
或SOME
。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 允许子查询引用具有数据修改副作用的存储函数,例如将行插入表中。例如,如果
f()
插入行,则以下查询可以修改数据SELECT ... WHERE x IN (SELECT f() ...);
这种行为是 SQL 标准的扩展。在 MySQL 中,它可能会产生非确定性结果,因为
f()
可能会在给定查询的不同执行中执行不同的次数,具体取决于优化器如何处理它。对于基于语句或混合格式的复制,这种不确定性的一个含义是,这样的查询可能会在源和它的副本上产生不同的结果。