情况:
一家公司有很多项目 一个项目有很多标签
一个项目只属于一家公司 标签可以属于多个项目
公司必须能够访问自己的标签
示例1:
在第一张图片中,公司的所有标签都可以通过projects / project_tag获得。但是如果删除了所有项目,那么公司的标签将不再可访问,因为project_tag和项目之间的链接已经消失。 即使没有项目,标签也应该以某种方式始终与公司相关联。
示例2(标签也与公司相关联):
在第二张图片中,它应该有效,但现在这是一个循环参考' ??? 对于像这样的问题,什么应该是最好的解决方案? 外键怎么样?
问题最终是: 如何针对这种情况正确设置数据库/数据模型?
第二个例子中出现问题的示例:
companies:
id=1, name=MyCompany
id=2, name=OtherCompany
tags:
id=1, company_id=1, name=MyTag
id=2, company_id=2, name=OtherTag
projects:
id=1, company_id=1, name=MyProject
project_tag:
project_id=1, tag_id=1
project_id=1, tag_id=2 --> THIS ROW IS NOT VALID!
最后一个project_tag行无效,因为:
相关联
项目1 与 company_id 1 相关联 tag_id 2 与 company_id 2
更新: 感谢所有人提供的信息!
根据接受的答案,PostgreSQL的CREATE查询将变为:
CREATE TABLE companies (
id SERIAL PRIMARY KEY NOT NULL,
name TEXT NOT NULL
);
CREATE TABLE projects (
id SERIAL PRIMARY KEY NOT NULL,
company_id INT NOT NULL,
name TEXT NOT NULL,
UNIQUE (id, company_id),
FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE RESTRICT ON UPDATE CASCADE
);
CREATE TABLE tags (
id SERIAL PRIMARY KEY NOT NULL,
company_id INT NOT NULL,
name TEXT NOT NULL,
UNIQUE (id, company_id),
FOREIGN KEY (company_id) REFERENCES companies (id) ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE project_tag (
id SERIAL PRIMARY KEY NOT NULL,
company_id INT NOT NULL,
project_id INT NOT NULL,
tag_id INT NOT NULL,
UNIQUE (company_id, project_id, tag_id),
FOREIGN KEY (company_id, project_id) REFERENCES projects (company_id, id) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (company_id, tag_id) REFERENCES tags (company_id, id) ON DELETE CASCADE ON UPDATE CASCADE
);
测试:
- 在相同的company_id 中检查插入project_tag中的行(否则: 否认)
- 无法将重复行插入project_tag
- 如果删除项目,则也会删除链接的 project_tag行 - 如果删除了代码,则也会删除已链接的 project_tag行 - 如果在仍有项目的情况下拆除公司,则拒绝拆除(参见项目表:ON DELETE RESTRICT)
- 如果删除了公司(没有项目),则所有链接的标签也将被删除
答案 0 :(得分:1)
首先,你的第二个模型绝对正确,并且没有任何循环引用。
您应该将Company_ID
Company
作为 FK 传送到Tags
和Project
并将其设为非空 。
然后,您应将TAG_ID
和Project_ID
作为 F.K 传输到Project_Tag
并将其组合在一起。并且无需将Company_ID
Project
和Tag
(我们在上一段中传输)传输到Project_Tag
。
现在,最后的问题,你的最终要求如何:
这条行没有用!
您无法通过ER 捕获它。您应该编写一些函数,触发器或存储过程来捕获和控制它。
修改强>:
基于@ reaanb的评论和他的好答案here:你可以通过这种方式控制这种约束,只需要一点点冗余:
CREATE TABLE Project(
project_id INT NOT NULL,
company_id INT NOT NULL,
PRIMARY KEY (project_id),
FOREIGN KEY (company_id) REFERENCES Company (id),
UNIQUE KEY (project_id, company_id)
);
CREATE TABLE Tag(
tag_id INT NOT NULL,
company_id INT NOT NULL,
PRIMARY KEY (tag_id),
FOREIGN KEY (company_id) REFERENCES Company (id),
UNIQUE KEY (tag_id, company_id)
);
CREATE TABLE Project_Tags(
id INT NOT NULL,
company_id INT NOT NULL,
project_id INT NOT NULL,
tag_id INT NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY (tag_id, project_id)
FOREIGN KEY (project_id, company_id) REFERENCES Project (project_id, company_id),
FOREIGN KEY (tag_id, company_id) REFERENCES Tag (tag_id, company_id),
);