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
这种行为似乎没有记录(我已经看过,但没有发现对这种行为的引用)。
我想使用此行为来实施一些业务规则,并希望确保这样做是安全的。
- 这是否符合任何 SQL 规范?
- 这可能将来会改变吗?
插图(抱歉,我不能在评论中这样做,需要格式化):
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。为了使复合类型具有一致的排序和索引行为,这是必要的。。我想这解决了你的问题。
在正常情况下,将 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
这种行为似乎没有记录(我已经看过,但没有发现对这种行为的引用)。
我想使用此行为来实施一些业务规则,并希望确保这样做是安全的。
- 这是否符合任何 SQL 规范?
- 这可能将来会改变吗?
插图(抱歉,我不能在评论中这样做,需要格式化):
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。为了使复合类型具有一致的排序和索引行为,这是必要的。。我想这解决了你的问题。