复杂的数据库关系(联结表)

Posted

技术标签:

【中文标题】复杂的数据库关系(联结表)【英文标题】:Complex Database Relations (Junction Tables) 【发布时间】:2011-09-28 21:50:05 【问题描述】:

我的问题是关于将两个联结表合并为一个的想法,用于类似相关的表。请阅读以了解我的意思。另请注意,这确实是我面临的一个问题,因此与这个论坛有关。这只是一个具有广泛影响的话题,我希望能引起各专业人士的更多参与,以便对“最佳实践”进行更好的普查。

我有一个相当具有挑战性的数据库设计问题。我希望这将是一个许多人可以贡献和学习的维基。为了让这更容易,我创建了一组图形,并将问题分解为 1) 过程和 2) 结构。

流程步骤

    已提出文档(出版物)请求 (DocRequest)。 如果该出版物尚不存在,则会创建一个新出版物。 会保留运行日志 (StatusReport) 以了解完成请求的进度。

注意:对于任何给定的出版物,可能有许多 DocRequests 和 StatusReports(包括更新)

数据库结构

注意:DocRequest 和 StatusReport 表都有许多字段和支持表,未在附图中显示。此外,特定的 Publication 是这些表中所有记录所属的主记录。

--当前实施--

注意:这种设计的主要缺陷是,每当您创建新的 DocRequest 和 StatusReport 记录时,您还必须在 Publications 表(其作用类似于联结表)中创建一个新记录,但这结果还创建了一个新的出版物。这不是我们想要的行为。

--典型实现--(对于这种类型的关系)

注意:这没问题,并且可能是理想的,但会处理对 DocRequest 和 StatusReport 表的更新,将它们独立链接到它们所属的出版物。

--我的首选实现-- (对于这种特殊情况)

注意:我在这里的想法只是将双联结表合并为一个。在这种情况下,只要 DocRequest 或 StatusReport 发生插入,联结表就会获得一条新记录。我可能会用触发器来处理这个问题。

讨论

现在开始讨论。如果您认为这是一个坏主意,我想从我的数据库开发人员那里知道,以及由此可能产生的问题。我认为记录的净数应该与两个单独的联结表相同,实际上通过节省额外的 ID 列来使用更少的空间。 :)

让我知道你们的想法。我真的很想让很多人参与这个讨论。干杯! :)

【问题讨论】:

一个文档请求可以创建多个文档,一个文档是多个请求的结果,两者都不是,还是两者兼而有之?一份状态报告与多份文档相关,多份文档与一份状态报告相关,两者都不相关,还是两者都相关?文件请求和状态报告之间是否存在关系?您提出的三种设计在这些方面有所不同,因此您必须明确说明。 从业务角度定义出版物的属性是什么?即,出版物是否可以是或是文档请求或状态报告的结果,或两者兼而有之,或者两者都不是,因此您正在尝试创建类型子类型结构? “StatusReport”是指报告的状态还是一种报告(因此是出版物)? “状态报告”是否与文件请求的状态、将满足文件请求的出版物的状态有关,还是两者兼而有之? 另外,您可能需要编辑您的问题以减少它被关闭的机会。 “如果你问这个问题的动机是‘我想参加关于______的讨论’,那么你不应该在这里问。” FAQ @Adam & Thomas:对于任何产品,都有多个出版物与之相关联。对于任何给定的发布,可以有多个对该发布的各种更改的请求,并且每个请求可以对原始请求进行多次更新。如果有帮助,我可以创建一个图表吗?另外,Thomas,请再次查看“流程步骤”,这可能会回答您的问题。它们是连续的。 【参考方案1】:

我认为您考虑连接表是在伤害自己。想想表格吧。

由于 StatusReport 与文档请求的状态有关, 您需要一张以某种方式将这两个联系起来的表格。 “StatusReport”对于存储有关文档请求状态的事实的表来说是一个糟糕的名称。 “ID”对于任何表中的任何列来说都是一个糟糕的名称。 发布的 id 号似乎与文档请求有关,而不是与请求的状态有关。 (你说,“如果说出版物不存在,则创建一个新出版物。”坦率地说,这已经接近了没有意义的边缘。)所以出版物编号几乎肯定属于 DocRequest 表。

参考您首选实现的图表,我将删除表 TripleJunction,并将 StatusReport 替换为此。

-- Predicate: Document request number (doc_request_id) has status (status) 
--            as of date and time (status_as_of).
create table document_request_status (
  doc_request_id integer not null references DocRequest (id),
  status_as_of timestamp not null default current_timestamp,
  status varchar(10) not null,
  -- other columns go here
  primary key (doc_request_id, status_as_of)
);

【讨论】:

是的,告诉我。几个月来,我一直在努力思考这个设计的要求。这是我能想到的最好的。更简单地说,我们有一个产品。对于该产品,我们需要各种出版物。这些出版物首先通过网络表单请求,然后创建。创建后,我们会跟踪其开发进度。诀窍是我们需要原始请求的运行日志(历史记录)(更改不是 SQL 更新,而是插入,因此是多对多)以及随附的状态报告及其更新(实际上是插入)。更清晰?喂。 其实我错了。在重新考虑之后,我确信 StatusReport 引用了特定出版物的进度。 Publications 和 StatusReports 的起点都是 Request。另外,请注意,StatusReports 和 Requests 包含来自实际 Web 表单的数据。表名反映了它们建模的真实对象。我们实质上是将以前的纸质流程转变为带有数据库的数字流程。至于“ID”,我个人更喜欢它,因为我的加入看起来像on ProductID = Products.ID 这个!! -- 前几天我有机会见到了我的老教授,他和 Catcall 一样指出,我认为关系是错误的。我在这里所拥有的实际上并不是真正的多对多关系。它实际上是属于一组 DocRequest 条目的一组 StatusReport 条目。解决方案是删除 Publications 表并简单地将“FirstRequest”字段添加到 DocRequest 表,并添加一个到 StatusReport 表,这两个字段都充当 DocRequest 主键的外键。我花了一段时间才到达那里,但感谢您的意见:)

以上是关于复杂的数据库关系(联结表)的主要内容,如果未能解决你的问题,请参考以下文章

联结表

第12课 联结表

如何在实体关系图中表示联结表?

1 小时 SQL 极速入门

SQL的联结

SQL的联结