下列程式码会建立数据表,而不会引发任何错误:
CREATE TABLE test(
ID INTEGER NULL,
CONSTRAINT PK_test PRIMARY KEY(ID)
)
请注意,我无法像预期的那样插入NULL:
INSERT INTO test
VALUES(1),(NULL)
ERROR: null value in column "id" violates not-null constraint
DETAIL: Failing row contains (null).
********** Error **********
ERROR: null value in column "id" violates not-null constraint
SQL state: 23502
Detail: Failing row contains (null).
为什么我可以创建一个定义自相矛盾的表?ID列被显式声明为NULLable,但作为PRIMARY KEY的一部分,它不能隐式为空。这有意义吗?
编辑:如果这个自相矛盾的CREATE TABLE就这样失败了,不是更好吗?
5条答案
按热度按时间u5rb5r591#
因为
PRIMARY KEY
使包含的列NOT NULL
自动。我引用the manual here:主键约束条件指定表的一列或多列只能包含唯一(非重复)的非空值。从技术上讲,
PRIMARY KEY
只是UNIQUE
和NOT NULL
的组合。大胆强调我的。
我运行了一个测试,以确认
NOT NULL
与PRIMARY KEY
约束(在当前的实现中,在版本13中重新测试)结合使用时是完全冗余的。NOT NULL
约束即使在删除PK约束后仍保持,而不管在创建时显式的NOT NULL
子句。第一个
小提琴
如果
CREATE TABLE
语句中包含NULL
,则行为相同。如果列应该是
NOT NULL
,那么在代码库中冗余地保留NOT NULL
也不会有什么坏处。如果您后来决定改变PK约束,您可能会忘记标记列NOT NULL
-或者它是否应该是NOT NULL
。Postgres TODO wiki中有一个条目将
NOT NULL
从PK约束中分离出来。因此,这可能会在未来的版本中更改:将NOT NULL约束条件信息移至pg_constraint
目前,NOT NULL约束条件存储在pg_attribute中,没有指定其来源,例如主键。一个明显的问题是删除PRIMARY KEY约束条件并不会删除NOT NULL约束条件指定。另一个问题是,我们可能应该强制NOT NULL从父表传播到子表,就像CHECK约束条件一样。(但是删除PRIMARY KEY会影响子表吗?)
新增问题的答案
如果这个自相矛盾的CREATE TABLE就这样失败了,不是更好吗?
如上所述,这
(目前)100%等同于:
因为
NULL
在此上下文中被视为噪声字。我们不希望后者失败,所以这不是一个选择。
9rnv2umw2#
如果我没记错的话,文件上提到:
null
基本上是一个被忽略的干扰词primary key
强制非空和唯一约束请参阅:
qxsslcnc3#
如果正如@ErwinBrandstetter所说,PRIMARY KEY仅仅是UNIQUE和NOT NULL的组合,那么可以使用一个没有
NOT NULL
的UNIQUE
约束来代替PRIMARY KEY
。例如:这样,您可以执行以下操作:
agyaoht74#
谈到NOT NULL,有很多方法可以确保它。不仅仅是将PostgreSQL作为一个关系数据库引擎:
1.列约束。
1.表约束条件(单个NOT NULL或复杂布尔表达式)
1.索引定义,
1.将任何NULL更改为“其他内容”的触发器。甚至可能还有其他方法。
一个就够了。没有其他的就意味着我们有矛盾?我不这么认为。
dvtswwa35#
PRIMARY KEY
列被强制为**NOT NULL
**。文档如下所示:
添加主键将自动为主键中列出的列或列组创建唯一的B树索引,并且将****强制将列标记为NOT NULL。