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_id
和 part_id
应该是 2 个不同表中的主键,您当前的表 Link
应该是这些表的连接表。然后你可以让Main
的link_id
引用第一个表的link_id
。
@choroba 运行代码当前给了我:foreign key mismatch - "Main" referencing "Link": INSERT INTO Main (main_id, link_id) VALUES (1,1);
@forpas 你想把它扩展成答案吗?
【参考方案1】:
我会提出不同的设计。
link_id
和 part_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 通常所有的实体,如 link 或 part 都有某种描述。无论如何,如果不需要,那么您可以拥有一个只有 1 列的表格。但是,每个链接至少应该有一个部分的约束不能仅由 sql 强制执行。在您的应用程序代码中,您应该确保仅当您有一对新插入的链接和部件作为第二步插入Links_Parts
时,才在Links
中插入新行。此外,在Links_Parts
中更新或删除后,您可能需要触发器来捕获孤立链接。以上是关于SQLite中的多对多链接表外键建模的主要内容,如果未能解决你的问题,请参考以下文章