奇怪的"所有"在"哪里"

car*_*arl 8 mysql sql

问题存在于MySQL的最新版本中,所以我甚至怀疑这可能是一个错误.

这是两个表:

t1(id int), values (10),(2)
t2(id int), values (0),(null),(1)
Run Code Online (Sandbox Code Playgroud)

执行:

select id from t1 where id > all (select id from t2);
Run Code Online (Sandbox Code Playgroud)

返回结果集:

+------+
| id   |
+------+
|   10 |
|    2 |
+------+
Run Code Online (Sandbox Code Playgroud)

根据我的知识和页面http://dev.mysql.com/doc/refman/5.5/en/all-subqueries.html

该语句应返回空结果!因为"where"中的每个判断都会导致null,如下所示:

select id > all (select id from t2)  as c1 from t1;
Run Code Online (Sandbox Code Playgroud)

收益:

+------+
| c1   |
+------+
| NULL |
| NULL |
+------+
Run Code Online (Sandbox Code Playgroud)

实际上select id from t1 where null;什么也没有回报

最后,我尝试了这个:

explain extended select id from t1 where id > all (select id from t2);
show warnings;
Run Code Online (Sandbox Code Playgroud)
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                             |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | select `test`.`t1`.`id` AS `id` from `test`.`t1` where <not>((`test`.`t1`.`id` <= (select max(`test`.`t2`.`id`) from `test`.`t2`))) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

1排(0.00秒)

我们可以看到MySQL优化了原始SQL,这实际上适合结果集.

但我不认为优化的SQL等于原始的SQL.

我错了吗?

Mic*_*uen 8

更新:进一步分析和展开MySQL的> ALL奇怪实现.这个答案应该被视为特定于MySQL.因此,对于进一步的免责声明,此处的答案解释> ALL不适用于其他RDBMS(除非有其他RDBMS复制了MySQL实现).从构造> ALL到内部的转换MAX仅适用于MySQL.

这个:

select id from t1 where id > all (select id from t2); 
Run Code Online (Sandbox Code Playgroud)

在语义上等同于:

select id from t1 where id > (select max(id) from t2); 
Run Code Online (Sandbox Code Playgroud)

由于select max(id) from t2返回1,第二个查询具体化为:

select id from t1 where id > 1
Run Code Online (Sandbox Code Playgroud)

这就是为什么它同时返回10,并2从表t1


应用NULL规则的一个实例是您使用NOT IN时的示例:

DDL:

create table t1(id int);

insert into t1 values (10),(2);


create table t2(id int); 

insert into t2 values (0),(null),(1);
Run Code Online (Sandbox Code Playgroud)

查询:

select * from t1 where id not in (select id from t2);

-- above is evaluated same as the following query, so the rules about null applies,
-- hence the above and following query will not return any record.    

select * from t1 where id <> 0 and id <> null and id <> 1;



-- to eliminate null side-effect, do this:
select * from t1 where id not in (select id from t2 where id is not null);

-- which is equivalent to this:
select * from t1 where id <> 0 and id <> 1;
Run Code Online (Sandbox Code Playgroud)

最后两个查询返回102,而前两种查询返回空集

现场测试:http://www.sqlfiddle.com/#!2/82865/1

希望这些示例能够消除您对NULL规则的困惑.


关于

但我不认为优化的sql等于原始的.

优化的sql是这样的:

select `test`.`t1`.`id` AS `id` from `test`.`t1` where <not>((`
test`.`t1`.`id` <= (select max(`test`.`t2`.`id`) from `test`.`t2`)))
Run Code Online (Sandbox Code Playgroud)

这实际上等同于您的原始查询: select id from t1 where id > all (select id from t2);

该构造t1.field > all (select t2.field from t2)只是一个语法糖:

t1.field > (select max(t2.field) from t2)
Run Code Online (Sandbox Code Playgroud)

如果您将在MySql的优化SQL上应用DeMorgan定理:

not (t1.id <= (select max(t2.id) from t2))
Run Code Online (Sandbox Code Playgroud)

这相当于:

t1.id > (select max(t2.id) from t2)
Run Code Online (Sandbox Code Playgroud)

这又相当于语法糖ALL:

t1.id > ALL(select t2.id from t2)
Run Code Online (Sandbox Code Playgroud)

  • 只有在子查询永远不能包含NULL时,查询的初始"语义等效"重写才有效.如果子查询可以返回空值,则重写无效. (2认同)

Mar*_*ith 5

这是MySQL中的一个错误(在此报告和验证).

该修复程序将在5.6.7(下一个5.6x版本)以及下一个主要树(5.7x)中提供

与MySQL文档中规定的行为和ANSI标准中规定的行为不同.

此外,它在MySQL中甚至不一致,当子查询引用表时,与子查询包含(相同)文字值时相比,您得到的结果不同.

CREATE TABLE t2
  (
     id INT
  );

INSERT INTO t2
VALUES      (0),
            (NULL),
            (1);

/*Returns row with 10*/
SELECT *
FROM   (SELECT 10 AS id) T
WHERE  id > ALL (SELECT id
                 FROM   t2);

/*Returns no rows. Explain Plan says "Impossible Where"*/
SELECT *
FROM   (SELECT 10 AS id) T
WHERE  id > ALL (SELECT 0
                 UNION ALL
                 SELECT NULL
                 UNION ALL
                 SELECT 1); 
Run Code Online (Sandbox Code Playgroud)

根据规范,第二种行为是正确的.如何10 > ALL( (0),(null),(1) )进行逻辑评估如下

10 > 0 =  TRUE
10 > NULL =  UNKNOWN
10 > 1 =  TRUE
Run Code Online (Sandbox Code Playgroud)

根据三值逻辑的规则

TRUE AND UNKNOWN AND TRUE = UNKNOWN
Run Code Online (Sandbox Code Playgroud)

所以应该返回此行.请参阅明确说明的ANSI规范

的"结果R <comp op> <quantifier> T"是隐含的应用导出<comparison predicate>" R <comp op> RT"每一行RTT:

因此,当TNullable为Nullable 时,这不是语义上有效的优化.规范的完整部分转载如下.

8.7

     Function

     Specify a quantified comparison.

     Format

     <quantified comparison predicate> ::=
          <row value constructor> <comp op> <quantifier> <table subquery>


     <quantifier> ::= <all> | <some>

     <all> ::= ALL

     <some> ::= SOME | ANY


     Syntax Rules

     1) The <row value constructor> shall be of the same degree as the
        result of the <table subquery>.

     2) The data types of the values of the <row value constructor>
        shall be respectively comparable to those of the columns of the
        <table subquery>.

     3) The collating sequence for each pair of respective values in
        the <quantified comparison predicate> is determined in the same
        manner as described in Subclause 8.2, "<comparison predicate>".

     Access Rules

        None.

     General Rules

     1) Let R be the result of the <row value constructor> and let T be
        the result of the <table subquery>.

     2) The result of "R <comp op> <quantifier> T" is derived by the
        application of the implied <comparison predicate> "R <comp op>
        RT" to every row RT in T:

        Case:

        a) If T is empty or if the implied <comparison predicate> is
          true for every row RT in T, then "R <comp op> <all> T" is
          true.

        b) If the implied <comparison predicate> is false for at least
          one row RT in T, then "R <comp op> <all> T" is false.

        c) If the implied <comparison predicate> is true for at least
          one row RT in T, then "R <comp op> <some> T" is true.

        d) If T is empty or if the implied <comparison predicate> is
          false for every row RT in T, then "R <comp op> <some> T" is
          false.

        e) If "R <comp op> <quantifier> T" is neither true nor false,
          then it is unknown.
Run Code Online (Sandbox Code Playgroud)