web-dev-qa-db-ja.com

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

なぜ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
16
Anil

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つの列をチェックすると、 "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             |
+----+-----+-----------+---------------+---------------+

これは意外かもしれません。 1つは妥当に見えます(x IS NULL)と(NOT x IS NULL)は互いに逆です。他のこと(どちらも " x IS NULL "も" x IS NOT NULL "もtrue)で、奇妙に見えます。

しかし、これは PostgreSQLのドキュメント が言うべきことです:

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

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

17
joanolo