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에 대해 전체 레코드를 확인하고 있다는 사실을 고려하고 있습니까? (You are
joanolo

@joanolo 네. id실제 코드베이스에서 확인하도록 코드를 전환 했지만 문제를 검색하는 데 몇 시간을 소비 한 후에 만 ​​가능합니다.
Anil

1
그 날 것으로 보인다 rec_variable IS NOT NULL경우 확인되는 모든 열이 NULL NOT 동안, rec_variable IS NULL경우 확인하고 있습니다 모든 열이 NULL입니다. 따라서 NOT rec_variable IS NULL"내부에 무엇이 있습니까?"라는 질문에 대한 대답은 내가 예상 한 것입니다.
Anil

답변:


17

두 가지 상황을 구별해야합니다. 하나의 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               | 
+----+-----+-------------+-----------------+-----------------+

이것은 당신과 내가 기대하는 것입니다. 하나의 COLUMN을 NULL에 대해 점검하고 있으며 "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)은 서로 반대입니다. 다른 것 ( "x IS NULL"도 "x IS NOT NULL"도 사실이 아님)은 이상하게 보입니다.

그러나 이것이 PostgreSQL 설명서에 나와있는 내용입니다.

표현식이 행 값인 경우 행 표현식 자체가 널이거나 모든 행의 필드가 널인 경우 IS NULL은 true이고 행 표현식 자체가 널이 아니고 모든 행의 필드가있는 경우 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) 여부를 확인하려고 할 때 편리합니다.
Anil

1
@Anil : 당신이 언급 한 유스 케이스가 전에 나타났습니다 : stackoverflow.com/questions/21021102/…
Erwin Brandstetter
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.