PostgreSQLの(x IS NOT NULL)vs(NOT x IS NULL)


16

なぜx IS NOT NULL等しくないのNOT x IS NULLですか?

このコード:

CREATE TABLE bug_test (
    id int,
    name text
);

INSERT INTO bug_test
VALUES (1, NULL);

DO $$
DECLARE
    v_bug_test bug_test;
BEGIN
    RAISE NOTICE '%: %', v_bug_test, (v_bug_test IS NULL);
    RAISE NOTICE '%: %', v_bug_test, (v_bug_test IS NOT NULL);
    RAISE NOTICE '%: %', v_bug_test, (NOT v_bug_test IS NULL);

    SELECT *
    INTO v_bug_test
    FROM bug_test
    WHERE id = 1;

    RAISE NOTICE '%: %', v_bug_test, (v_bug_test IS NULL);
    RAISE NOTICE '%: %', v_bug_test, (v_bug_test IS NOT NULL);
    RAISE NOTICE '%: %', v_bug_test, (NOT v_bug_test IS NULL);
END
$$;

DROP TABLE bug_test;

次の出力が得られます。

(,): t
(,): f
(,): f
(1,): f
(1,): f ???
(1,): t

私はこの出力を取得することを期待していますが:

(,): t
(,): f
(,): f
(1,): f
(1,): t <<<
(1,): t

1
実際にレコード全体をNULLでチェックしているという事実を考慮していますか?(あなたは
joanolo

@joanoloはい。id実際のコードベースで確認するためにコードを切り替えましたが、問題を探すのに数時間費やした後です。
アニル

1
その私には思えるrec_variable IS NOT NULLかどうかをチェックされ、すべての列がNULLではありませんが、rec_variable IS NULLかどうかをチェックされ、すべての列がNULLです。したがってNOT rec_variable IS NULL、私が期待したものを与えます-「何かが中にありますか?」という質問に対する答え。
アニル

回答:


17

2つの状況を区別する必要があります。1つのCOLUMNをNULLと比較するか、ROW(RECORD)全体をNULLと比較します。

次のクエリを検討してください。

SELECT
    id, 
    txt, 
    txt     IS NULL AS txt_is_null, 
    NOT txt IS NULL AS not_txt_is_null, 
    txt IS NOT NULL AS txt_is_not_null
FROM
    (VALUES
        (1::integer, NULL::text)
    ) 
    AS x(id, txt) ;

あなたはこれを得る:

+----+-----+-------------+-----------------+-----------------+
| id | txt | txt_is_null | not_txt_is_null | txt_is_not_null | 
+----+-----+-------------+-----------------+-----------------+
|  1 |     | t           | f               | f               | 
+----+-----+-------------+-----------------+-----------------+

これは、あなたと私が期待するものだと思います。NULLに対して1つのCOLUMNをチェックすると、「txt IS NOT NULL」と「NOT txt IS NULL」が等価になります。

ただし、別のチェックを行う場合:

SELECT
    id, 
    txt, 
    x       IS NULL AS x_is_null,
    NOT x   IS NULL AS not_x_is_null,
    x   IS NOT NULL AS x_is_not_null
FROM
    (VALUES
        (1, NULL)
    ) 
    AS x(id, txt) ;

その後、あなたは得る

+----+-----+-----------+---------------+---------------+
| id | txt | x_is_null | not_x_is_null | x_is_not_null |
+----+-----+-----------+---------------+---------------+
|  1 |     | f         | t             | f             |
+----+-----+-----------+---------------+---------------+

これは驚くかもしれません。合理的に見えるもの(x IS NULL)と(NOT x IS NULL)は互いに反対です。もう1つ(「x IS NULL」も「x IS NOT NULL」も真ではないという事実)は奇妙に見えます。

ただし、これはPostgreSQLのドキュメントに記載されているとおりです。

式が行値である場合、行式自体がnullまたは行のすべてのフィールドがnullの場合、IS NULLはtrueです。一方、行式自体がnullでなく、すべての行のフィールドがnullの場合、IS NOT NULLはtrueです。非ヌル。この動作のため、IS NULLおよびIS NOT NULLは、行値の式に対して常に逆の結果を返すとは限りません。特に、NULLフィールドと非NULLフィールドの両方を含む行値式は、両方のテストでfalseを返します。場合によっては、行IS DISTINCT FROM NULLまたは行IS NOT DISTINCT FROM NULLを書き込む方が望ましい場合があります。これは、行フィールドで追加テストを行わずに、行全体の値がnullであるかどうかを単純にチェックします。

私はこれまでにnullに対して行値比較を使用したことはないと思いますが、可能性がある場合は、いくつかのユースケースがあるかもしれないと思います。とにかく一般的だとは思いません。


はい、説明は理にかなっており、これを投稿してから行った実験の結果と一致しています。レコード変数全体を比較した理由は、私の背景が非SQL言語であるためです。これは非常に一般的です。ユースケースに関しては、フィールドごとに行うのではなく、レコード変数のすべてのフィールドが埋められているかどうかを確認したい場合(rec IS NOT NULL)に便利です。
アニル

1
@Anil:正確にあなたが言及ユースケースを前にポップアップしていますstackoverflow.com/questions/21021102/...
アーウィンBrandstetter
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.