postgresql 为什么我可以创建一个在可空列上具有PRIMARY KEY的表?

kqhtkvqz  于 2022-12-12  发布在  PostgreSQL
关注(0)|答案(5)|浏览(106)

下列程式码会建立数据表,而不会引发任何错误:

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就这样失败了,不是更好吗?

u5rb5r59

u5rb5r591#

因为PRIMARY KEY使包含的列NOT NULL自动。我引用the manual here
主键约束条件指定表的一列或多列只能包含唯一(非重复)的非空值。从技术上讲,PRIMARY KEY只是UNIQUENOT NULL的组合。
大胆强调我的。
我运行了一个测试,以确认NOT NULLPRIMARY 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就这样失败了,不是更好吗?
如上所述,这

foo_id INTEGER NULL PRIMARY KEY

(目前)100%等同于:

foo_id INTEGER PRIMARY KEY

因为NULL在此上下文中被视为噪声字。
我们不希望后者失败,所以这不是一个选择。

9rnv2umw

9rnv2umw2#

如果我没记错的话,文件上提到:

  • create table语句中的null基本上是一个被忽略的干扰词
  • primary key强制非空和唯一约束

请参阅:

# create table test (id int null primary key);
CREATE TABLE
# \d test
     Table "public.test"
 Column |  Type   | Modifiers 
--------+---------+-----------
 id     | integer | not null
Indexes:
    "test_pkey" PRIMARY KEY, btree (id)
qxsslcnc

qxsslcnc3#

如果正如@ErwinBrandstetter所说,PRIMARY KEY仅仅是UNIQUE和NOT NULL的组合,那么可以使用一个没有NOT NULLUNIQUE约束来代替PRIMARY KEY。例如:

CREATE TABLE test(
    id integer,
    CONSTRAINT test_id_key UNIQUE(id)
);

这样,您可以执行以下操作:

INSERT INTO test (id) VALUES (NULL);
INSERT INTO test (id) VALUES (NULL);
INSERT INTO test (id) VALUES (NULL);
agyaoht7

agyaoht74#

谈到NOT NULL,有很多方法可以确保它。不仅仅是将PostgreSQL作为一个关系数据库引擎:
1.列约束。
1.表约束条件(单个NOT NULL或复杂布尔表达式)
1.索引定义,
1.将任何NULL更改为“其他内容”的触发器。甚至可能还有其他方法。
一个就够了。没有其他的就意味着我们有矛盾?我不这么认为。

dvtswwa3

dvtswwa35#

PRIMARY KEY被强制为**NOT NULL**。
文档如下所示:

添加主键将自动为主键中列出的列或列组创建唯一的B树索引,并且将****强制将列标记为NOT NULL

相关问题