SQLite中的多对多链接表外键建模

Posted

技术标签:

【中文标题】SQLite中的多对多链接表外键建模【英文标题】:Many-to-Many Link Table Foreign Key Modeling in SQLite 【发布时间】:2022-01-06 15:40:16 【问题描述】:

我在 SQLite 中有以下两个表:

CREATE TABLE `Link` (
    `link_id`   integer NOT NULL,
    `part_id`   integer NOT NULL,
    CONSTRAINT `link_pk` PRIMARY KEY(`link_id`,`part_id`)
);
CREATE TABLE `Main` (
    `main_id`   integer NOT NULL PRIMARY KEY AUTOINCREMENT,
    `link_id`   integer NOT NULL REFERENCES `Link`(`link_id`)
);
INSERT INTO `Link` (link_id, part_id) VALUES (1,10);
INSERT INTO `Link` (link_id, part_id) VALUES (1,11);
INSERT INTO `Link` (link_id, part_id) VALUES (1,12);
INSERT INTO `Link` (link_id, part_id) VALUES (2,15);

INSERT INTO `Main` (main_id, link_id) VALUES (1,1);
INSERT INTO `Main` (main_id, link_id) VALUES (2,1);
INSERT INTO `Main` (main_id, link_id) VALUES (3,2);

许多Main 行可能引用相同的链接ID,许多Link 行可能具有相同的链接ID,这样select * from Main natural join Link where main_id=1 将返回N 行,select * from Main where link_id=1 将返回K 行。 link id很重要,原始数据每个main有1个link id,每个link有N个part id。

使用上面的模式,由于外键约束 (foreign key mismatch - "Main" referencing "Link": INSERT INTO Main (main_id, link_id) VALUES (1,1);),我无法在 Main 中插入任何行,大概是因为 the composite key requirement。我可以通过删除外键约束来实现这一点,但是我显然错过了一个约束。反转密钥的方向也不起作用,因为如上所述,这是一个多对多的关系。有没有办法在 SQLite 中正确地对此进行建模,其约束条件是 Link 中的每个 link_id 至少存在一行 Main

【问题讨论】:

哪些行不能插入?示例中的三行可以插入就好了。 你应该重新考虑你的设计。 link_idpart_id 应该是 2 个不同表中的主键,您当前的表 Link 应该是这些表的连接表。然后你可以让Mainlink_id引用第一个表的link_id @choroba 运行代码当前给了我:foreign key mismatch - "Main" referencing "Link": INSERT INTO Main (main_id, link_id) VALUES (1,1); @forpas 你想把它扩展成答案吗? 【参考方案1】:

我会提出不同的设计。

link_idpart_id 2 个实体中的每一个都应该是 2 个表中的主键,例如:

CREATE TABLE Links (
    link_id INTEGER PRIMARY KEY,
    link_description TEXT
);

CREATE TABLE Parts (
    part_id INTEGER PRIMARY KEY,
    part_description TEXT
);

然后,创建上述表的联结表(如您当前的Link 表):

CREATE TABLE Links_Parts (
    link_id INTEGER NOT NULL REFERENCES Links(link_id),
    part_id INTEGER NOT NULL REFERENCES Parts(part_id),
    PRIMARY KEY(link_id, part_id)
);

还有表Main

CREATE TABLE Main (
    main_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
    link_id INTEGER NOT NULL REFERENCES Links(link_id)
);

所有关系都在那里,如果设置外键支持,则可以保证引用完整性:

PRAGMA foreign_keys = ON;

查看简化的demo。

【讨论】:

鉴于链接没有描述或其他属性,因此只有一列的表太奇怪了。但是,这并不强制要求至少有一部分的链接。有没有办法做到这一点? @byteit101 通常所有的实体,如 linkpart 都有某种描述。无论如何,如果不需要,那么您可以拥有一个只有 1 列的表格。但是,每个链接至少应该有一个部分的约束不能仅由 sql 强制执行。在您的应用程序代码中,您应该确保仅当您有一对新插入的链接和部件作为第二步插入Links_Parts 时,才在Links 中插入新行。此外,在Links_Parts 中更新或删除后,您可能需要触发器来捕获孤立链接。

以上是关于SQLite中的多对多链接表外键建模的主要内容,如果未能解决你的问题,请参考以下文章

建模数据仓库中的多对多关系

更新 Prisma 中的多对多关系

DW中尺寸之间的多对多关系-更好的建模?

渴望加载 Laravel 5 与两个外键的多对多关系

没有连接表的多对多映射

实体框架中的多对多关系导致无限循环