【问题标题】:Why can I create a table with PRIMARY KEY on a nullable column?为什么我可以在可为空的列上创建带有 PRIMARY KEY 的表?
【发布时间】:2013-11-29 03:48:35
【问题描述】:

以下代码创建一个表而不会引发任何错误:

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 就在那里失败了不是更好吗?

【问题讨论】:

    标签: postgresql constraints primary-key ddl postgresql-9.3


    【解决方案1】:

    因为PRIMARY KEY 使包含列NOT NULL 自动。我引用the manual here

    主键约束指定一个或多个列 表只能包含唯一(非重复)、非空值。 从技术上讲,PRIMARY KEY 只是UNIQUENOT NULL 的组合

    我的大胆强调。

    我进行了一项测试,以确认 NOT NULLPRIMARY KEY 约束(在当前实现中,在版本 13 中重新测试)完全冗余。 NOT NULL 约束仍然存在,即使在删除 PK 约束之后,无论创建时显式的 NOT NULL 子句如何。

    CREATE TABLE foo (foo_id int PRIMARY KEY);
    ALTER TABLE foo DROP CONSTRAINT foo_pkey;
    
    db=# \d foo
       table »public.foo«
     column |  type   | attribute
    --------+---------+-----------
     foo_id | integer | not null    -- stays
    

    db小提琴here

    如果NULL 包含在CREATE TABLE 语句中,则行为相同。

    如果列应该是NOT NULL,在代码存储库中冗余保留NOT NULL 仍然没有什么坏处。如果您稍后决定更改 PK 约束,您可能会忘记标记列 NOT NULL - 或者它是否应该是 NOT NULL

    有一个item in the Postgres TODO wikiNOT 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 在此上下文中被视为干扰词。
    我们不希望后者失败。所以这不是一个选择。

    【讨论】:

    • 关于“稍后删除主键”的细微差别
    • @AlexKuznetsov:实际上我进行了测试,证明自己在这个细节上是错误的。然而,其余的适用。请参阅修改后的答案。
    【解决方案2】:

    如果没记错的话,文档会提到:

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

    见:

    # 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)
    

    【讨论】:

      【解决方案3】:

      如果正如@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);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-04-28
        • 1970-01-01
        • 2021-07-26
        • 2017-05-01
        • 2021-02-01
        • 1970-01-01
        • 2016-09-26
        相关资源
        最近更新 更多