8

この問題は MySQL の最新バージョンに存在するため、それがバグであるとは思えません。

以下に 2 つのテーブルを示します。

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 が元の SQL と等しいとは思いません。

私が間違っている?

4

3 に答える 3

8

更新> ALL:MySQLの奇妙な実装をさらに分析して展開したとき。この回答は、MySQL固有と見なす必要があります。したがって、さらなる免責事項として、ここでの回答に関する説明は> ALL、他のRDBMSには適用されません(MySQL実装をコピーした他のRDBMSがない限り)。> 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); 

1を返すのでselect max(id) from t2、2番目のクエリは次のようになります。

select id from t1 where id > 1

10これが、テーブルt1と2テーブルt1の両方を返す理由です。


NULLルールが適用されている例の1つは、次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;

最後の2つのクエリはと10を返します2が、最初の2つのクエリは空のセットを返します

ライブテスト:http ://www.sqlfiddle.com/#!2/82865/1

これらの例がNULLルールとの混乱を解消することを願っています。


それにかんする

しかし、最適化されたSQLが元の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にドモルガンの定理を適用する場合:

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)
于 2012-07-13T01:39:02.237 に答える
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); 

2番目の動作は、仕様に従って正しいです。10 > ALL( (0),(null),(1) )次のように論理的に評価する方法

10 > 0 =  TRUE
10 > NULL =  UNKNOWN
10 > 1 =  TRUE

3値論理のルールの下で

TRUE AND UNKNOWN AND TRUE = UNKNOWN

したがって、この行は返されません。明確に述べているANSI仕様を参照してください

""の結果は、 :のすべての行にR <comp op> <quantifier> T暗黙の<comparison predicate>" "を適用することによって得られます。R <comp op> RTRTT

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.
于 2012-07-15T14:19:08.313 に答える
4

更新(2012-07-15)問題はMySQLのみに限定されており、Chromeの多くのsqlfiddleタブ間をタブで移動しているときに混乱した可能性があります。Postgresqlには問題はありません。そのNULL動作は、SQL Serverと同様に、SELECT句とWHERE句の両方で一貫しています。

驚いたことに、私は今あなたと同じように混乱しています。SQLServerで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 |

当然、2番目のクエリ(WHERE句を含む)は行を返さないはずです。どのSQLServerが正しく実行するか。列の結果であることに同意しませんが(そうあるべきです)0C11、SQLServerが一貫していることを称賛します。

次に、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 |

2番目のクエリの出力は正しいと思いますが、SELECT句(最初のクエリ)に埋め込まれた条件はそうではないことを示しています。私はこの矛盾が嫌いです。

印象的な段落の修正:MySQLに問題があります。Postgresqlの実装は正しく、SELECT句とWHERE句の両方で同じ結果が得られ、SELECTでNULLが返され、WHERE句で空の行が返されます。

さて、 PostgresqlまたはMySqlフォーラムでこの質問をしたかったのですが、WHERE句の条件とSELECT句に埋め込まれた条件の結果に不一致があるのはなぜですか。

私たちのためにこの矛盾をさらに説明することができるstackoverflowの親族の魂があることを願っています:-)


糖衣構文がどんなに甘くてもALL、もう使いたくないです。それは、WHERE句とSELECTに埋め込まれたものの間で一貫性のない結果をもたらします。私はMAXとにかくすべてのクエリで使用します、私見の意図は英語のようなものよりも明確です、ALL私が使用し続ける必要があるより多くの理由MAX

印象的な段落の修正ALL: MySQLに欠陥のある実装があるという理由だけで嫌悪感を抱くべきではありません;-)

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);

出力は両方のMAXRDBMSで一貫しています。

-- 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 |


さらに、すべてのRDBMS間MAX一貫性があります。

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);

ライブテスト:



それを釘付けにするために、に実装id > ALLするのはMySQLだけid > (SELECT MAXです。PostgresqlとSqlServerはどちらもとして解釈id > ALL(0,NULL,1)されるid > 0 AND id > NULL AND id > 1ため、PostgresqlとSqlServerはどちらも同じ出力を生成します。

NULLルールの照明は、 NULL値に関するMartinSmithの洞察から得られます。なんで?

MySQLのALL問題はMySQLのみに限定されており、非常に一貫性がありません。MySQLはWHERE句でに変換ALLされます。MAXSELECT句を使用している間、MySQLは連鎖ANDに変換ALLされます。

他のRDBMSは連鎖> ALLANDとして実装され、ALL式のNULLに関する規則は、SELECT句とWHERE句の両方に適用され、SELECT句とWHERE句の両方で一貫した結果が得られます。そして、それらのルールはANSQLSQLに準拠していますNULLALL

于 2012-07-13T02:33:12.213 に答える