PostgreSQL 9.4 - 比较NULL值

时间:2015-12-26 19:04:16

标签: postgresql postgresql-9.4

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

SELECT NULL = NULL;

返回NULL

在比较任意行时(大多数情况下)这是正确的,如the documentation, 9.23.5. Row Constructor Comparison

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

返回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;

返回TRUE

这种行为似乎没有记录(我查看并发现没有对行为的引用)。

我想使用此行为来实现某些业务规则,并希望确保安全。

  1. 这与任何SQL规范一致吗?
  2. 可能这将来会改变吗?

2 个答案:

答案 0 :(得分:4)

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

答案 1 :(得分:0)

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

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关于此的咆哮)
  • 可能其他行为会导致更奇怪的人工制品