13

次のクエリを使用しています。

select count(*) from Table1 where CurrentDateTime>'2012-05-28 15:34:02.403504' and Error not in ('Timeout','Connection Error');

驚くべきことに、このステートメントにはエラー値が NULL の行は含まれていません。私の意図は、エラー値が「タイムアウト」(または)「接続エラー」の行のみをフィルタリングすることです。正しい結果を取得するには、追加の条件 (OR Error is NULL) を指定する必要があります。

MYSQL が NULL 値の結果を除外するのはなぜですか? IN キーワードはブール値の結果 (1/0) を返すと思っていましたが、一部の MYSQL キーワードはブール値を返さず、NULL も返す可能性があることを理解しました....しかし、NULL を特別なものとして扱うのはなぜですか?

4

6 に答える 6

32

これ :

Error not in ('Timeout','Connection Error');

意味的には次と同等です。

Error <> 'TimeOut' AND Error <> 'Connection Error'

null 比較に関する規則は IN にも適用されます。したがって、Error の値が NULL の場合、データベースは式を真にすることができません。

修正するには、次のようにします。

COALESCE(Error,'') not in ('Timeout','Connection Error');

またはさらに良い:

Error IS NULL OR Error not in ('Timeout','Connection Error');

またはさらに良い:

 CASE WHEN Error IS NULL THEN 1
 ELSE Error not in ('Timeout','Connection Error') THEN 1
 END = 1

ORショートサーキットではありません。CASE は何らかの方法でクエリをショートすることができます


おそらく具体的な例は、なぜNULL NOT IN expression何も返さないのかを説明することができます:

このデータを考えると:http://www.sqlfiddle.com/#!2/0d5da/11

create table tbl
(
  msg varchar(100) null,
  description varchar(100) not null
  );


insert into tbl values
('hi', 'greet'),
(null, 'nothing');

そして、あなたはこの表現をします:

select 'hulk' as x, msg, description 
from tbl where msg not in ('bruce','banner');

それは「こんにちは」だけを出力します。

NOT IN は次のように変換されます。

select 'hulk' as x, msg, description 
from tbl where msg <> 'bruce' and msg <> 'banner';

NULL <> 'bruce'決められない、真でもない、偽でもない

NULL <> 'banner'判断できない 真でもない 偽でもない

したがって、null 値の式は、実質的に次のように解決されます。

can't be determined AND can't bedetermined

実際、RDBMS が SELECT でブール値をサポートしている場合 (MySQL、Postgresql など)、その理由を確認できます: http://www.sqlfiddle.com/#!2/d41d8/828

select null <> 'Bruce' 

それはnullを返します。

これも null を返します。

select null <> 'Bruce' and null <> 'Banner'

を使用している場合NOT IN、これは基本的に AND 式です。

NULL AND NULL

結果は NULL になります。だから、あなたがやっているようなものです:http://www.sqlfiddle.com/#!2/0d5da/12

select * from tbl where null

何も返されません

于 2012-05-30T05:27:56.433 に答える
1

同じフォーラムに 2 回投稿して申し訳ありませんが、別の例を示したいと思います。

このフォーラムの [2] で @Wagner Bianchi が次のように述べていることに同意します。

さらに、これは振る舞いであってはなりません。Mysql の設計者は、[1] で文書化されたこの決定を下したときに間違っていると思います。デザインは違うはずです。説明させてください:あなたは比較するときにそれを知っています

select (2) not in (1, 4, 3);
    you will get:
        +----------------------+
        | (2) not in (1, 4, 3) |
        +----------------------+
        |                    1 |
        +----------------------+
        1 row in set (0.00 sec)

しかし、リストに少なくとも 1 つの NULL がある場合:

select (2) not in (1, NULL, 3);
    throws:
        +-------------------------+
        | (2) not in (1, NULL, 3) |
        +-------------------------+
        |                    NULL |
        +-------------------------+
        1 row in set (0.00 sec)
    This is pretty absurd.

これに混乱したのは私たちが初めてではありません。[2] を参照

参考文献:

[1] http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_in

[2] http://blog.9minutesnooze.com/sql-not-in-subquery-null/comment-page-1/#comment-86954

于 2014-10-29T15:49:59.980 に答える
1

null は未定義であるため、null は null と等しくありません。null を常に明示的に処理する必要があります。

于 2012-05-30T05:25:15.167 に答える
1

INNULL左辺の式が の場合に返しますNULLNULL値を取得するには、次のことを行う必要があります。

select count(*) from Table1 where CurrentDateTime>'2012-05-28 15:34:02.403504' and (Error not in ('Timeout','Connection Error') or Error is null);
于 2012-05-30T05:27:32.767 に答える
1

IN三価を返しますBOOLEAN(値として受け入れNULLます)。NOT INの 3 価の否定を返し、 のIN否定NULLは aNULLです。

1から1,000,000inまでのすべての数字を含むテーブルとid、次のクエリがあるとします。

SELECT  *
FROM    mytable
WHERE   id IN (1, 2, NULL)

またはそれに相当するもの:

SELECT  *
FROM    mytable
WHERE   id = ANY
             (
             SELECT  1
             UNION ALL
             SELECT  2
             UNION ALL
             SELECT  NULL
             )

述語は、他のすべての値に対してandを返すTRUEため、andが返されます。12NULL12

その反対に:

SELECT  *
FROM    mytable
WHERE   id NOT IN (1, 2, NULL)

、 また

SELECT  *
FROM    mytable
WHERE   id <> ALL
             (
             SELECT  1
             UNION ALL
             SELECT  2
             UNION ALL
             SELECT  NULL
             )

の場合、述語はFALSEfor 1and 2and NULLfor 他のすべての値を返すため、何も返されません。

ブール否定は、演算子 ( =to <>) だけでなく量指定子 ( ANYto ALL) も変更することに注意してください。

于 2012-05-30T07:28:24.897 に答える
1

@Michael Buenの答えは私の場合の正しい答えでしたが、理由を簡単に説明しましょう。

@Michael は彼の投稿で次のように述べています。


Error not in ('Timeout','Connection Error');

意味的には次と同等です。

エラー <> 'タイムアウト' AND エラー <> '接続エラー'

null 比較に関する規則は IN にも適用されます。したがって、Error の値が NULL の場合、データベースは式を真にすることができません。

[1] で、IN が NULL で失敗する理由を理解するための彼の最も重要な声明を確認するこの文を見つけました。[1] の仕様 (「仕様」) では、次のようになります。

そうです、悲しいことにMysqlはそのような場合に失われるということです. Mysql の設計者はこれを行うべきではなかったと思います。なぜなら、2 を NULL と比較すると、Mysql はそれらが異なることを認識できるはずであり、単に間違った結果をスローするだけではないからです。たとえば、次のようにしました。

select id from TABLE where id not in (COLUMN WITH NULLS);

その後、EMPTY の結果がスローされます。しかし。私が行った場合

select id from TABLE where id not in (COLUMN WITH OUT NULLS);

それは正しい結果を示しています。したがって、IN 演算子を使用する場合は、NULL を除外する必要があります。これはユーザーとして望ましい動作ではありませんが、[1] の仕様に記載されています。仕様を読まなくても DEDUCE ができるという意味で、言語とテクノロジーはもっとシンプルであるべきだと思います。確かに、2 は NULL とは異なります。より高いレベルの抽象化の間違いを制御および処理するのは私が担当する必要がありますが、MySQL は NULL を特定の値と比較するときに FALSE の結果をスローする必要があります。

仕様の参照: [1] http://dev.mysql.com/doc/refman/5.6/en/type-conversion.html

于 2014-10-29T15:29:11.370 に答える