Sql 两个递归多对多关系之间的约束

Sql 两个递归多对多关系之间的约束,sql,postgresql,many-to-many,data-modeling,Sql,Postgresql,Many To Many,Data Modeling,我有以下表格用于创建任意数量的不同类型的项目 CREATE TABLE item_types ( id SERIAL, PRIMARY KEY (id) -- Other columns omitted ); CREATE TABLE items ( id SERIAL, itemtype integer NOT NULL, PRIMARY KEY (id), FOREIGN KEY (itemtype) REFERENCES item_

我有以下表格用于创建任意数量的不同类型的项目

CREATE TABLE item_types (
    id SERIAL,
    PRIMARY KEY (id)
    -- Other columns omitted
);

CREATE TABLE items (
    id SERIAL,
    itemtype integer NOT NULL,
    PRIMARY KEY (id),
    FOREIGN KEY (itemtype) REFERENCES item_types (id)
    -- Other columns omitted
);
items
表有一个称为
item\u relationship
的递归多对多关系

CREATE TABLE item_relationships (
    itemid1 integer,
    itemid2 integer,
    PRIMARY KEY (itemid1, itemid2),
    FOREIGN KEY (itemid1) REFERENCES items (id),
    FOREIGN KEY (itemid2) REFERENCES items (id) 
);
item\u-types
表有一个递归的多对多关系,称为
item\u-relationship\u-types

CREATE TABLE item_relationship_types (
    type1 integer,
    type2 integer,
    PRIMARY KEY (type1, type2),
    FOREIGN KEY (type1) REFERENCES item_types (id),
    FOREIGN KEY (type2) REFERENCES item_types (id)  
);
现在,我想做的是以某种方式设置一个约束,即您不能意外地创建一个无效的
项目关系
,即在任何
项目关系类型
中都找不到项目的
项目类型
。我有两个问题

  • 这样的限制有意义吗?我认为插入一个错误的关系是一个很容易在业务逻辑中发生的错误,因此在DB中进行约束很重要

  • 实际实现约束的合理方式是什么

    • 这并不完美,但似乎有效


    一种可能的方法是使用代理主键扩展
    项关系类型
    表:

    CREATE TABLE item_relationship_types (
        id integer SERIAL,
        type1 integer,
        type2 integer,
        PRIMARY KEY (id),
        UNIQUE (type1, type2),
        FOREIGN KEY (type1) REFERENCES item_types (id),
        FOREIGN KEY (type2) REFERENCES item_types (id)  
    );
    
    然后将指向该代理键的外键添加到
    item_relationships
    表中:

    CREATE TABLE item_relationships (
        itemid1 integer,
        itemid2 integer,
        type_rel_id integer not null,
        PRIMARY KEY (itemid1, itemid2),
        FOREIGN KEY (itemid1) REFERENCES items (id),
        FOREIGN KEY (itemid2) REFERENCES items (id),
        FOREIGN KEY (type_rel_id) REFERENCES item_relationship_types (id)  
    );
    

    您还需要创建一个触发器,防止在
    项目关系
    表中输入
    type\u rel\u id
    值,该值指向
    项目关系
    表中类型与这两个项目不相关的项目。

    注:此处不涉及递归;这是一种模型->实例继承模式,“递归”到底是什么意思?例如,当表
    项关系类型
    具有以下记录时:
    (1,2)、(2,3)、(3,4)
    ,是否意味着类型1不仅与类型2相关,而且与类型3和4相关?@wildplasser感谢您的澄清。@kordirko在您的示例1中间接与3和4相关,但在(1,3)和(1,4)类型的项目之间创建项目_关系应该是不可能的。仅在您列出的记录之间。如果有人从
    项目关系类型
    中删除记录,而没有从
    项目关系
    中删除相应的行,该怎么办?完整性将被破坏。是的,你也需要处理那个案子。(不幸的是,这里不可能进行级联)@D4rt我回滚到原始版本。它似乎是正确的。您正在将
    项目(id)
    项目类型(id)
    进行比较。
    items(id)
    中的值范围为101到109,而
    item_类型(id)
    中的值范围为1到9,因此它们从不匹配。您的代码在两个插入上都失败。这里,第一对插入成功,第二对失败,正如预期的那样。我会再查一遍。我试过扳机的变体,但它被证明太慢了。我扩展了您的想法,没有创建代理键,而是将
    type1
    type2
    item\u relationship\u types
    直接添加到
    item\u relationships
    。在
    item\u关系中
    我添加了
    外键(type1,itemid1)引用items(itemtype,id)
    ,对于
    type2
    itemid2
    也一样。然后我添加了
    外键(type1,type2)引用项\关系\类型(type1,type2)
    。这有效地解决了约束问题,但不得不将
    type1
    type2
    添加到
    item\u关系
    中会让人感觉不舒服。对这个解决方案有什么想法吗?
    CREATE TABLE item_relationships (
        itemid1 integer,
        itemid2 integer,
        type_rel_id integer not null,
        PRIMARY KEY (itemid1, itemid2),
        FOREIGN KEY (itemid1) REFERENCES items (id),
        FOREIGN KEY (itemid2) REFERENCES items (id),
        FOREIGN KEY (type_rel_id) REFERENCES item_relationship_types (id)  
    );