多对多自引用表

Posted

技术标签:

【中文标题】多对多自引用表【英文标题】:Many-to-many self-referential table 【发布时间】:2010-11-11 02:40:38 【问题描述】:

有没有好办法实现单表行间的多对多关系?

示例:存储单词同义词的表:

-- list of words
CREATE TABLE word (
    id    integer      PRIMARY KEY,
    word  varchar(32)  NOT NULL UNIQUE
);
INSERT INTO words (id, word) VALUES (1, 'revolve');
INSERT INTO words (id, word) VALUES (2, 'rotate');

-- M:M link between words
CREATE TABLE word_link (
    word1  integer      REFERENCES word(id) NOT NULL,
    word2  integer      REFERENCES word(id) NOT NULL,
    PRIMARY KEY (word1, word2)
);

明显的解决方案导致可能不是 1NF 表,包含重复数据:

INSERT INTO word_link(word1, word2) VALUES (1, 2);
INSERT INTO word_link(word1, word2) VALUES (2, 1);

虽然可以通过添加 (word1

那么有没有更好的(希望是通用的)方法来实现这种 M:M 关系?

【问题讨论】:

【参考方案1】:

在这种情况下,我会在 UPDATE 和 INSERT 上添加一个 CHECK CONSTRAINT 以强制 word1 始终小于 word2,反之亦然。

【讨论】:

【参考方案2】:

我将创建一个如下视图:

select distinct
    case when word1 < word2 then word1 else word2 end as word1,
    case when word1 < word2 then word2 else word1 end as word2
from
    word_link

这样,您始终拥有一个干净、没有重复且易于从中选择的列表。我发现这与建立多对多关系的方式一样干净。

【讨论】:

嗯...您的案例陈述对这两种情况都有相同的标准。我想你的意思是 word2 @Nathan:同样的条件,不同的结果。第一列总是使用较小的词,而第二列总是使用最大的。 问题不在于摆脱重复的 word_link(CHECK CONSTRAINT 可以完成所有工作),而是查询需要它们:“SELECT w.* FROM word w JOIN wold_link wl ON w .id=wl.word2 AND wl.word1=2" 不会返回 (1, 'revolve')。所以选择是在臃肿的查询“... ON (w.id=wl.word2 AND wl.word1=2) OR (w.id=wl.word1 AND wl.word1=1)”和具有一致性的臃肿表之间建立触发器

以上是关于多对多自引用表的主要内容,如果未能解决你的问题,请参考以下文章

带有额外列的多对多自引用原则

多对多自引用关系

sqlalchemy中的多对多自引用关系

从教义中的多对多自引用实体中获取孩子

如何使用 Doctrine 2 创建与额外字段的多对多自引用关联?

通过联结表进行多对多自连接