Postgresql 空组合类型和包含所有空列的组合类型之间的差异

Postgresql 空组合类型和包含所有空列的组合类型之间的差异,postgresql,null,distinct,postgresql-9.6,row-value-expression,Postgresql,Null,Distinct,Postgresql 9.6,Row Value Expression,空值和所有列都为空的行类型之间有什么区别吗?Postgres查询似乎能够区分差异(显示空列而不是空列),我想知道是否有什么我应该知道的。e、 g CREATE TYPE node AS ( rank integer , id integer ); CREATE TABLE hierarchy ( node node ); INSERT INTO hierarchy (node) VALUES (null); INSERT INTO hierarchy (node) VALUES

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

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;
空值和所有列都为空的行类型之间有什么区别吗?

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

SELECT null::node IS DISTINCT FROM (null, null)::node AS dist;
我同意这令人困惑。还有:

对于非空输入,
不同于
运算符相同。 但是,如果两个输入都为null,则返回false,如果只有一个输入,则返回false 输入为null,则返回true

事实证明,在上面的演示中有点不正确。尽管有进一步的暗示:

如果
表达式
是行值表达式,则当行 表达式本身为空或当所有行的字段为空时

因此我们有两种不同的情况,行值为null:

  • 表达式本身为空
  • 该行的所有字段均为空
  • 应该提到的是,当与
    不同于
    时,这两种情况仍然被认为是不同的。可能值得一份文档错误报告

    有什么我应该知道的吗?

    对。只要
    DISTINCT
    起作用,这两种变体都被认为是不同的:

    SELECT DISTINCT * FROM hierarchy;
    
    注意第二行不可见,因为psql以这种方式显示空值

    阻止(,)案例发生?

    针对您的评论:

    CREATE TABLE hierarchy (
      node node CHECK (node IS DISTINCT FROM (null, null)::node)
    );
    
    注意两件事:

  • 显式强制转换
    (null,null)::node
    是必需的
  • 仍然允许使用简单的空值,只有包含所有空值的行才违反约束

  • 检查数据库设计,因为所有列都为NULL的行在关系模型中没有意义。您总是需要一个唯一的主键来标识表中的每一行。行可以有一些空字段,但行的主键永远不应该为空。@aicastell将问题中的rowtype读取为复合类型。您的问题有许多语法错误(以及语义错误,f.ex.node既是复合类型又是表名)。你确定是你干的?
    (NULL,NULL)的奇怪行为是NULL
    来自SQL标准。但实际上,当处理
    外部连接时,它非常方便。您所显示的内容是不可能的。表和复合类型不能具有相同的名称。请修正你的问题使其有意义。并始终声明您正在使用的Postgres版本。因此,为了防止出现
    (,)
    情况,我必须添加
    检查(node1不同于(null,null))
    约束?@dbeacham:是的,但您需要显式类型转换。我在上面加了更多。
    SELECT DISTINCT * FROM hierarchy;
    
     node1
    ------
     (,)  
    
    (2 rows)
    
    CREATE TABLE hierarchy (
      node node CHECK (node IS DISTINCT FROM (null, null)::node)
    );