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操作的序列来实现。此方法不能用于ALLANYSOME

  • 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()可能执行不同的次数。

对于基于语句或混合格式的复制,这种不确定性的一个含义是,这样的查询可以在主服务器及其从属服务器上产生不同的结果。