PostgreSQL 9.4 - 比较 NULL 值

PostgreSQL 9.4 - Comparing NULL values

在正常情况下,将 NULL 值与任何其他值进行比较会得到另一个 NULL 值。

SELECT NULL = NULL;

Returns NULL


这在比较任意行时(大部分)成立,如 the documentation, 9.23.5. Row Constructor Comparison:

中所述
SELECT ROW(1, NULL, 'baz text') = ROW(1, NULL, 'baz text'); 

Returns NULL


但是,当比较明确定义的复合类型时,NULL 值被视为相等。

CREATE TYPE test_type AS (
    foo INTEGER,
    bar BIGINT,
    baz TEXT
);

SELECT (1, NULL, 'baz text')::test_type = (1, NULL, 'baz text')::test_type;

Returns TRUE

这种行为似乎没有记录(我已经看过,但没有发现对这种行为的引用)。

我想使用此行为来实施一些业务规则,并希望确保这样做是安全的。

  1. 这是否符合任何 SQL 规范?
  2. 可能将来会改变吗?

插图(抱歉,我不能在评论中这样做,需要格式化):

CREATE TYPE test_type AS (
    foo INTEGER
    , bar BIGINT
    , baz TEXT
    );

        -- plain table with three fields
CREATE TABLE test_table0 (
    foo INTEGER
    , bar BIGINT
    , baz TEXT
    );

        -- the same, but with a composite type
CREATE TABLE test_table1 (
        tt test_type
        );

INSERT INTO test_table0 (foo,bar,baz)
        VALUES (1, NULL, 'baz text');

INSERT INTO test_table1 (tt)
        VALUES( (1, NULL, 'baz text')::test_type) ;

        -- union needs a "whole row" -compare
SELECT * FROM test_table0
UNION
SELECT * FROM test_table0
        ;

        -- union needs a "whole row" -compare
        -- and type needs a whole "composite" compare
SELECT * FROM test_table1
UNION
SELECT * FROM test_table1
        ;

结果:

CREATE TYPE
CREATE TABLE
CREATE TABLE
INSERT 0 1
INSERT 0 1
 foo | bar |   baz    
-----+-----+----------
   1 |     | baz text
(1 row)

       tt        
-----------------
 (1,,"baz text")
(1 row)

  • 注意:比较的对象(类型实例和元组)不是NULL,只是它们的一些元素。
  • 我确实认为这是预期的行为
  • 恕我直言,这接近于在复合键中允许 NULL 元素的问题,(请参阅 Chris Date 的咆哮)
  • 其他行为可能会导致更奇怪的人工制品

我在 official documentation 中找到了这个: [...] 在比较两个复合类型值的其他上下文中,两个 NULL 字段值被认为是相等的,并且 NULL 是被认为大于非 NULL。为了使复合类型具有一致的排序和索引行为,这是必要的。。我想这解决了你的问题。