(x IS KHÔNG NULL) so với (KHÔNG x IS NULL) trong PostgreSQL


16

Tại sao x IS NOT NULLkhông bằng NOT x IS NULL?

Mã này:

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;

đưa ra kết quả sau:

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

trong khi tôi mong đợi để có được đầu ra này:

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

1
Bạn đang xem xét thực tế rằng bạn đang thực sự kiểm tra toàn bộ hồ sơ chống lại NULL. (Bạn là
joanolo

@joanolo Vâng. Tôi đã chuyển mã để kiểm tra idtrong cơ sở mã thực sự của mình, nhưng chỉ sau vài giờ tìm kiếm một vấn đề.
Anil

1
Dường như với tôi rec_variable IS NOT NULLlà kiểm tra xem tất cả các cột KHÔNG phải là NULL, trong khi rec_variable IS NULLkiểm tra xem tất cả các cột có phải là NULL không. Do đó NOT rec_variable IS NULLđưa ra những gì tôi mong đợi - một câu trả lời cho câu hỏi "có gì bên trong không?".
Anil

Câu trả lời:


17

Bạn phải phân biệt hai tình huống: bạn so sánh một CỘT với NULL hoặc bạn so sánh toàn bộ ROW (RECORD) với NULL.

Hãy xem xét các truy vấn sau:

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

Bạn nhận được điều này:

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

Đây là, tôi đoán, những gì bạn và tôi sẽ mong đợi. Bạn đang kiểm tra một CỘT với NULL và bạn nhận được "txt IS NOT NULL" và "KHÔNG txt IS NULL" là tương đương.

Tuy nhiên, nếu bạn thực hiện một kiểm tra khác:

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

Sau đó, bạn nhận được

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

Điều này có thể gây ngạc nhiên. Một điều có vẻ hợp lý (x IS NULL) và (KHÔNG x IS NULL) trái ngược với nhau. Một điều khác (thực tế là cả "x IS NULL" hay "x IS NOT NULL" đều không đúng sự thật), trông thật kỳ lạ.

Tuy nhiên, đây là những gì tài liệu PostgreQuery nói rằng sẽ xảy ra:

Nếu biểu thức có giá trị hàng, thì IS NULL là đúng khi chính biểu thức hàng là null hoặc khi tất cả các trường của hàng là null, trong khi IS KHÔNG NULL là đúng khi chính biểu thức hàng là null và tất cả các trường của hàng là không null. Do hành vi này, IS NULL và IS NOT NULL không luôn trả về kết quả nghịch đảo cho các biểu thức có giá trị hàng; đặc biệt, một biểu thức có giá trị hàng chứa cả trường null và không null sẽ trả về false cho cả hai bài kiểm tra. Trong một số trường hợp, có thể tốt hơn là viết hàng IS DISTINCT TỪ NULL hoặc hàng KHÔNG PHẢI DISTINCT TỪ NULL, điều này sẽ đơn giản kiểm tra xem giá trị hàng tổng thể có null hay không mà không có bất kỳ kiểm tra bổ sung nào trên các trường hàng.

Tôi phải thú nhận rằng tôi đã không nghĩ rằng mình đã từng sử dụng một so sánh có giá trị so với null, nhưng tôi đoán rằng nếu khả năng là có, có thể có một số trường hợp sử dụng cho nó. Tôi không nghĩ là phổ biến, dù sao đi nữa.


Vâng, lời giải thích có ý nghĩa và phù hợp với kết quả của các thí nghiệm tôi đã làm kể từ khi đăng bài này. Tại sao tôi so sánh toàn bộ biến bản ghi là vì nền tảng của tôi là các ngôn ngữ không phải là SQL, nơi điều này khá phổ biến. Về các trường hợp sử dụng, tôi cho rằng điều này rất hữu ích khi người ta muốn kiểm tra xem tất cả các trường trong một biến bản ghi có được điền không (rec IS NOT NULL), thay vì thực hiện theo từng trường.
Anil

1
@Anil: Chính xác là trường hợp sử dụng mà bạn đề cập đã xuất hiện trước đó: stackoverflow.com/questions/21021102/ợi
Erwin Brandstetter
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.