【问题标题】:unique constraint on table表的唯一约束
【发布时间】:2018-02-02 16:04:55
【问题描述】:

我有以下表格定义:

CREATE TABLE modules(
    id  integer PRIMARY KEY)

CREATE TABLE submodules(
    id          integer PRIMARY KEY,
    identnum    integer)

CREATE TABLE usablesubmodules(
    moduleid    integer REFERENCES modules(id),
    submoduleid integer REFERENCES submodules(id))

基本上是一个模块表和一个子模块表。模块只能使用由可用子模块表定义的某些子模块。如何定义一个约束,以使任何给定模块可用的子模块的 identnum 值都是唯一的?也就是说,以下查询必须为任何给定的 moduleid 'x' 返回一组唯一的 identnum 值:

SELECT identnum FROM submodules
INNER JOIN usablesubmodules ON submodules.id = usablesubmodules.submoduleid
WHERE usablesubmodules.moduleid = x

如果这很重要,我正在使用 postgresql 9.6。

【问题讨论】:

    标签: sql postgresql unique-constraint postgresql-9.6


    【解决方案1】:

    submodules.identnum 上设置唯一性和not null 约束。

    CREATE TABLE submodules(
        id          integer PRIMARY KEY,
        identnum    integer UNIQUE NOT NULL);
    

    usablesubmodules 表上创建复合 PK。

    CREATE TABLE usablesubmodules(
        moduleid    integer REFERENCES modules(id),
        submoduleid integer REFERENCES submodules(id)
        PRIMARY KEY (moduleid, submoduleid));
    

    ...或...

    CREATE TABLE usablesubmodules(
        moduleid    integer REFERENCES modules(id),
        identnum    integer REFERENCES submodules(identnum)
        PRIMARY KEY (moduleid, identnum));
    

    以上任何一项都可以保证您永远不会将identnum 与一个模块关联超过一次。

    submodules 表中identnum 的唯一性约束确保您对于给定的identnum 永远只有一个submodules 记录。

    usablesubmodules 上的复合主键确保您永远不会拥有多个具有相同 moduleididentnum 的记录。

    【讨论】:

    • 我提供了一个更新的答案,以确保 2 个表格的唯一性。
    • identnum 在子模块表中不会是唯一的。子模块 1 和子模块 2 可以有相同的identnum,只要它们不能被同一个模块使用。
    • 在这种情况下,您想要的是不可能的 - 任何针对子模块表创建约束的尝试都容易出现竞争条件,因为该表上可能会发生并发写入。没有什么可以阻止更新子模块 #2 的记录以更改其 identnum,同时正在发出另一个请求以将子模块 #2 链接到可能已经具有具有旧或新 identnum 的子模块的模块 - 在任何一种情况下,您都可能会得到由于竞争条件,结果错误。
    【解决方案2】:

    您实际上有两个约束:

    • {module,submodule} 必须是唯一的
    • 这对必须存在于 allowed_pa​​irs 中(它也必须是唯一的)

    -- \i tmp.sql

    CREATE TABLE modules(
            m_id integer PRIMARY KEY
            );
    
    CREATE TABLE submodules(
            s_id integer PRIMARY KEY
            );
    
    CREATE TABLE allowed_submodules(
            m_id integer NOT NULL REFERENCES modules(m_id)
            , s_id integer NOT NULL REFERENCES submodules(s_id)
            , PRIMARY KEY (m_id, s_id)
            );
    
    CREATE TABLE used_submodules(
            m_id integer NOT NULL
            , s_id integer NOT NULL
            , PRIMARY KEY (m_id, s_id)
            ,  FOREIGN KEY (m_id,s_id) REFERENCES allowed_submodules(m_id,s_id)
            );
    

    更新:如果您坚持保留(冗余,恕我直言)附加键列 identnum,以下是如何将其添加到 used_submodules表中。


    CREATE TABLE used_submodules(
            m_id integer NOT NULL
            , s_id integer NOT NULL
            ,  PRIMARY KEY (m_id, s_id)
            ,  FOREIGN KEY (m_id, s_id) REFERENCES allowed_submodules(m_id, s_id)
            , identnum integer NOT NULL
            ,  UNIQUE (m_id, identnum)
            );
    

    【讨论】:

    • 这不正确...您完全忽略了变量 identNum。
    • 也许是因为它是多余的?它有什么用途?
    • 这不是多余的。 identnum 将唯一标识可以使用它的模块范围内的子模块。对于给定的模块,它的所有子模块都将具有唯一的identnum。 Submodule1 和 Submodule2 可以具有相同的identnum,只要它们不能被同一个模块使用。这是一个有点奇怪的系统,但我没有以这种方式设计数据结构。我只需要使用它。
    • 如果你坚持添加它:添加它,并在 (module,identnum) 上加上一个 UNIQUE 约束`请注意你在这里输入 MVD-land。
    • 我可以在一个表的列和另一个表的列之间添加约束吗? IE。在 modules.id 和 submodules.identnum 之间?
    猜你喜欢
    • 2021-01-22
    • 2010-10-11
    • 2011-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-06
    • 2012-10-27
    • 2019-09-25
    相关资源
    最近更新 更多