如何正确设计数据库的这一部分(循环引用?)

显影123

情况:

一个公司有很多项目
一个项目有很多标签

一个项目仅属于一个公司
一个标签可以属于多个项目

一个公司必须有权访问自己的标签

范例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)
-如果公司(没有项目)被删除,则所有链接的标签也将被删除。

戈拉马里-伊朗

首先,您的第二个模型是绝对正确的,并且其中没有任何循环引用。

你应该发送Company_IDCompanyFKTagsProject,使其不为空

然后,你应该传递TAG_IDProject_IDFK s转换Project_Tag,使独特在一起。而且也没有必要发送Company_IDProjectTag(我们在前面的段落传输)到Project_Tag

现在,关于最后一个问题,您的最终要求:

此行无效!

无法通过ER捕获它您应该编写一些函数,触发器或存储过程来捕获和控制它。

编辑
基于@reaanb的评论和他在这里的出色回答:您可以通过这种方式控制此约束,并稍加冗余:

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),
);

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何循环在php数据库中的列的一部分

如何检查mysql数据库是否是用户的一部分

如何在MySQL中将字符串的一部分与大型数据库进行比较

如何使用Xcode附加到Firebase实时数据库的一部分

从数据库浏览记录时如何更新页面的一部分

如果复制 numpy 数组的一部分,如何正确取消引用?

使用ElasticSeach作为我的数据库一部分的主要来源

SQLCMD是数据库引擎或客户端工具的一部分吗?

仅下载Firebase中数据库参考的一部分?

数据库的字符串模板只取最后一部分

EF Core DBContext仅定位数据库的一部分

在访问数据库中搜索单词的一部分

在Ruby中查找数据库的一部分

如何在 FOR 循环中引用文件名的一部分?

如何引用数组的一部分?

如何正确完成本基本循环练习的第一部分?

如何返回对递归数据结构的一部分的引用?

成功设计会议室数据库架构后,如何获取网络响应中另一个记录的一部分的记录列表

Python-Selenium:如何访问网站的这一部分?

如何使用正则表达式删除文本的这一部分?

如何在我的代码的这一部分放入变量?

如何在此查询的这一部分使用标签?

如何减少我的代码的这一部分,使其不重复

Howard Hinnant的日期库:仅加载IANA时区数据库的一部分

通过点击特定的按钮显示数据库中的数据重定向后的一部分 - Laravel

回送是否将数据库的索引作为元数据的一部分提供?

将表 postgresql 的一部分移动到另一个数据库

表“ a”有一个条目,但是不能从查询的这一部分中引用它

如何从api的一部分接收数据到另一部分