情况:
一家公司有许多项目
一个项目有许多标记
一个项目只属于一家公司
标记可以属于多个项目
公司必须有权使用自己的标签
例1:
在第一张图片中,公司的所有标记都可以通过projects/project_标记获得。但是,如果删除了所有项目,则公司的标记将不再可访问,因为项目标记和项目之间的链接已不存在。
标签应该以某种方式始终链接到公司,即使没有项目。
示例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!
最后一个项目标记行无效,因为:
项目1链接到公司ID 1
标记ID 2链接到公司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
);
测试:
-在项目标记中插入的行在同一个公司ID上被选中(否则:
拒绝)
-无法在项目标记中插入重复行
-如果删除项目,链接的项目标记行也将被删除
-如果删除了标记,则链接的项目标记行也将被删除
-如果公司在仍有项目时被删除,则删除将被拒绝(请参见项目表:在删除限制时)
-如果删除了公司(没有项目),则所有链接的标记也将被删除
最佳答案
首先,您的第二个模型是绝对正确的,并且其中没有任何循环引用。
您应该将Company_ID
的Company
作为f.k发送到Tags
和Project
并使其不为空。
然后,您应该将TAG_ID
和Project_ID
作为f.ks传输到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),
);