一列已经声明UNIQUE,却仍保存了多条NULL,首先需要核对唯一性比较如何处理空值。PostgreSQL 17第5.5.3节说明,默认情况下,这种比较不把两个NULL看作相等。因此,唯一约束存在与多个空值能够出现,可以同时成立。[1]
对于多列唯一约束,文档讨论的是约束中列值的组合,而不是每一列都必须各自唯一。只有把约束涉及的列读完整,才能理解哪些记录正在被比较。原文明确指出,默认规则下,包含至少一个受约束列空值的重复行仍可能被保存。
例如,本文构造两列的识读情境:租户编号与外部编号一起受唯一约束,两行都记为“租户7、外部编号NULL”。在上述默认空值比较下,这组值不会仅因两个NULL就被认定为相同的唯一键。这个例子用于解释文档规则,未在数据库中建表或执行插入,也没有替代其他可能存在的约束检查。
若定义中采用NULLS NOT DISTINCT,空值在这项唯一性比较中就按不相异处理。文档同时说明,可以用NULLS DISTINCT明确写出默认行为。两种写法影响的是唯一约束怎样比较NULL,并不等于把整列改成禁止空值。
禁止空值是NOT NULL所表达的另一件事。第5.5.2节将它解释为该列不能取空值;第5.5.4节则说明,主键要求相应列值同时具有唯一性和非空性。因此,“有唯一约束”“空值参加相同键比较”和“根本不允许空值”应分别从定义中确认,不能互相替代。
阅读表结构时,较清楚的说明可以同时写明受约束的列组合、是否允许NULL,以及唯一比较采用哪种空值处理。业务人员说“编号不能重复”,还没有自动回答“编号暂缺时允许几条”的问题。这是本文提出的需求表达方法,不是对某个生产库的变更建议。
本文于2026年10月10日读取17版官方文档,不将未确认的网页首发日期补入来源。文档还提醒,SQL标准对这项默认空值处理留给实现决定,其他数据库可能采用不同规则。跨数据库讨论时,应保留产品与版本,再核对定义,不能把PostgreSQL 17的默认行为直接当成所有系统的共同结论。
信息来源
本文基于上述公开资料整理,未使用来源页面的图片、视频或嵌入媒体。