MySQL的最新版本存在问题,所以我甚至怀疑这可能是一个错误。
以下是两个表格:
t1(id int), values (10),(2)
t2(id int), values (0),(null),(1)
执行:
select id from t1 where id > all (select id from t2);
返回结果集:
+------+
| id |
+------+
| 10 |
| 2 |
+------+
根据我的知识和页面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;
返回:
+------+
| c1 |
+------+
| NULL |
| NULL |
+------+
实际上select id from t1 where null;
没有返回任何内容!
最后,我尝试了这个:
explain extended select id from t1 where id > all (select id from t2);
show warnings;
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------+
| 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`))) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------+
1行(0.00秒)
我们可以看到MySQL优化了原始SQL,这实际上符合结果集。
但我不认为优化的SQL等于原始的SQL。
我错了吗?
答案 0 :(得分:8)
更新:进一步分析和展开MySQL的> ALL
奇数实现。这个答案应该被视为特定于MySQL。因此,对于进一步的免责声明,有关> ALL
的答案的解释不适用于其他RDBMS(除非有其他RDBMS复制了MySQL实现)。从> ALL
到MAX
构造的内部转换仅适用于MySQL。
此:
select id from t1 where id > all (select id from t2);
在语义上等同于:
select id from t1 where id > (select max(id) from t2);
由于select max(id) from t2
返回1,因此第二个查询具体化为:
select id from t1 where id > 1
这就是它从表t1
返回10
和2
的原因
正在应用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);
查询:
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;
最后两个查询返回10
和2
,而前两个查询返回空集
实时测试: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`)))
这实际上与原始查询相同: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)
如果您将在MySql的优化SQL上应用DeMorgan定理:
not (t1.id <= (select max(t2.id) from t2))
这相当于:
t1.id > (select max(t2.id) from t2)
反过来相当于句法糖ALL
:
t1.id > ALL(select t2.id from t2)
答案 1 :(得分:5)
这是MySQL中的一个错误(Reported and verified here)。
该修复程序将在5.6.7(下一个5.6x版本)以及 下一个主要树(5.7x)
它differs from the stated behaviour in the MySQL docs和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);
根据规范,第二种行为是正确的。 10 > ALL( (0),(null),(1) )
如何按逻辑评估如下
10 > 0 = TRUE
10 > NULL = UNKNOWN
10 > 1 = TRUE
根据三值逻辑的规则
TRUE AND UNKNOWN AND TRUE = UNKNOWN
因此,此行应不返回。 See the ANSI specification明确说明
“
R <comp op> <quantifier> T
”的结果是由...导出的 应用隐含的<comparison predicate>
“R <comp op> RT
”RT
中的每一行T
:
因此,当T
为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.
答案 2 :(得分:4)
更新(2012-07-15)问题仅限于MySQL,也许我在浏览Chrome上的许多sqlfiddle选项卡时感到困惑。 Postgresql没有问题,它的NULL行为在SELECT和WHERE子句上都是一致的,与Sql Server相同。
很明显,我和你一样困惑,我在Sql Server上尝试了你的MySql查询:http://www.sqlfiddle.com/#!3/82865/6
-- query 1
select
case when id > all(select id from t2) then 1 else 0 end as c1
from t1;
-- query 2
select
*
from t1
where id > all(select id from t2);
第一个查询将0
返回给所有行。
| C1 |
------
| 0 |
| 0 |
当然,第二个查询(具有WHERE子句)不应返回任何行。哪个Sql Server正当地做了。 虽然我不同意的结果,但我赞赏Sql Server保持一致。 0
作为列C1
(应该是1
)
然后在MySql(http://www.sqlfiddle.com/#!2/82865/25)和Postgresql(http://www.sqlfiddle.com/#!1/82865/5)上的MySql查询中:
-- query 1
select
id > all(select id from t2) as c1
from t1;
-- query 2
select
*
from t1
where id > all(select id from t2);
MySql和Postgresql都产生了相同的输出:
MySql产生此输出:
| C1 |
----------
| (null) |
| (null) |
| ID |
------
| 10 |
| 2 |
我认为第二个查询具有正确的输出,但SELECT子句(第一个查询)的嵌入条件另有说明。我不喜欢这种不一致。
严格段落修正:MySQL有问题。 Postgresql实现是正确的,它的SELECT子句和WHERE子句产生相同的结果,它在SELECT上返回NULL,并在WHERE子句上返回空行。
现在,我想在 Postgresql或 MySql论坛上提出这个问题,为什么WHERE子句的条件和SELECT子句中嵌入的条件之间的结果存在差异。
我希望stackoverflow中有一个相似的灵魂可以为我们进一步解释这个不一致: - )
<击>
无论合成糖ALL
多么甜,我不再倾向于使用它了。它在WHERE子句和嵌入在SELECT上之间的结果不一致。无论如何,我在所有查询中使用MAX
,恕我直言,意图比英语ALL
更清晰,我需要继续使用MAX
的原因越多:
击>
严格的段落修正:我们不应该因为MySQL的实施存在缺陷而对ALL
产生厌恶; - )
在MySql和Postgresql上,MAX产生相同的输出
-- Query 1
select
id > all(select id from t2) as c1,
id > (select max(id) from t2) as c2
from t1;
-- Query 2
select
*
from t1
where id > all(select id from t2);
-- Query 3
select
*
from t1
where id > (select max(id) from t2);
MAX
输出在两个RDBMS上都是一致的。
-- Query 1 output:
| C1 | C2 |
---------------
| (null) | 1 |
| (null) | 1 |
-- Query 2 output:
MySql return this:
| ID |
------
| 10 |
| 2 |
Postgresql return empty row. Which is correct
-- Query 3 output:
| ID |
------
| 10 |
| 2 |
此外,MAX
在所有RDBMS中一致:
select
case when id > all(select id from t2) then 'Yes' else 'Oh No!' end as c1,
case when id > (select max(id) from t2) then 'Yes' else 'Oh No!' end as c2
from t1;
select
*
from t1
where id > all(select id from t2);
select
*
from t1
where id > (select max(id) from t2);
现场测试:
Sql Server:http://www.sqlfiddle.com/#!3/82865/10
Postgresql:http://www.sqlfiddle.com/#!1/82865/7
为了确定它,只有MySQL实现id > ALL
到id > (SELECT MAX
。 Postgresql和Sql Server都将id > ALL(0,NULL,1)
解释为id > 0 AND id > NULL AND id > 1
,因此Postgresql和Sql Server都会产生相同的输出。
关于NULL规则的启示来自Martin Smith对NULL values are excluded. Why?
的见解 MySQL的ALL
问题仅与MySQL隔离,它非常不一致。 MySQL在其WHERE子句上将ALL
翻译为MAX
;在其SELECT子句中,MySQL将ALL
转换为链接 AND。
其他RDBMS实现> ALL
作为链接 ANDs,ALL表达式上的NULL规则适用于它们的SELECT子句和WHERE子句,它们对SELECT子句和WHERE子句都有一致的结果。他们在NULL
ALL
上的规则是符合ANSQL SQL的