空复合类型和所有空列的复合类型之间的区别

Difference between null composite type and composite type with all null columns

空值和所有列都为空的行类型之间有什么区别吗? Postgres 查询似乎能够分辨出差异(显示空列而不是空白),我想知道是否有什么我应该注意的。例如

CREATE TYPE node AS (
   rank integer
 , id integer
);

CREATE TABLE hierarchy (
   node node
);

INSERT INTO hierarchy (node) VALUES (null);
INSERT INTO hierarchy (node) VALUES ((null, null));

SELECT *, node IS NULL AS check_null FROM hierarchy;
 node | check_null
------+------------
      | t
 (,)  | t

Is there any difference between a null value and a rowtype where all the columns are null?

NULL:node 仍然不同于 (null, null)::node:

SELECT null::node IS DISTINCT FROM (null, null)::node AS dist;
dist
----
t

我同意这令人困惑。还有the manual might be sharpened here,还有:

For non-null inputs, IS DISTINCT FROM is the same as the <> operator. However, if both inputs are null it returns false, and if only one input is null it returns true.

上面的demo看来有点不对。即使下面有提示:

If the expression is row-valued, then IS NULL is true when the row expression itself is null or when all the row's fields are null.

所以我们有两个行值为空的不同情况:

  1. 表达式本身为空。
  2. 该行的所有字段均为空。

值得一提的是,与IS DISTINCT FROM相比,这两种情况仍然被认为是不同。可能值得一份文档错误报告 ...

anything I should be aware of?

是的。无论 DISTINCT 在哪里发挥作用,两种变体都被认为是不同的:

SELECT DISTINCT * FROM hierarchy;
 node1
------
 (,)  

(2 rows)

注意第二个不可见的行,因为 psql 以这种方式显示空值。

To stop the (,) case from occurring ?

处理您的评论:

CREATE TABLE hierarchy (
  node node CHECK (node IS DISTINCT FROM (null, null)::node)
);

注意两点:

  1. 显式转换 (null, null)::node 是必要的。
  2. 仍然允许简单的 NULL 值,只有包含所有空值的行违反了约束。