【问题标题】:Database tables, one table referencing multiple unrelated tables数据库表,一张表引用多个不相关的表
【发布时间】:2010-10-22 17:15:45
【问题描述】:

这个问题在我搜索的各个论坛中出现过几次,但没有一个提供简洁的解决方案。

如果我有以下表格:

User
+- id
+- username
+- password

Article
+- id
+- title
+- content

我想加入他们以确定谁创建了哪些文章,我可以简单地将列 user_id 添加到 Article 以用作参考。或者,我正在添加一个中间表来显示谁/何时/什么,例如:

User
+- ...

Article
+- ...

ChangeHistory
+- id
+- article_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime

现在这很好,但是我正在开发的系统需要更加动态,因为可以轻松引入和集成新模块。所以现在如果我添加一个 Media 表,我需要在 ArticleMedia 之间拆分 ChangeHistory : p>

User
+- ...

Article
+- ...

Media
+- id
+- title
+- path

ArticleChangeHistory
+- id
+- article_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime

MediaChangeHistory
+- id
+- media_id
+- user_id
+- type [enum(insert, update, delete)]
+- datetime

随着许多模块的引入,这很快就会失控。每个模块都需要负责创建和管理它自己的 ChangeHistory 表。

TL;DR:我可以探索哪些实践来创建可以接收对多个其他不相关表的引用的中间表?我可以添加一个 *record_type* 字段,保存记录所属表的名称,但这很难看。我需要像“table ID”这样的东西来引用它来自的表。这样,当/如果添加或删除模块时,模型不会崩溃。

有什么想法吗?提前非常感谢。

【问题讨论】:

  • 您认为“表 ID”比“记录类型”更好吗?

标签: sql mysql database-design foreign-key-relationship


【解决方案1】:

根据我的经验,当开发人员试图让他们的系统真正“动态”时,他们实际上是在尝试为他们尚未想到的问题编写代码。这通常是一条糟糕的道路。一个模块包含两个表而不是一个表真的需要额外的工作吗?

在所有我看到的模式(或反模式?)试图制作一个通用的“做所有事情”表的情况下,它的表面都是平淡无奇的。 RDBMS 最适用于定义明确的问题区域。如果模块需要保留历史记录,那么模块应该添加一个历史记录表以与表本身一起使用。这也有一个巨大的优势,因为您可能希望在历史记录中保留不同类型的信息,具体取决于保留历史记录的表或模块。如果您有一个通用的历史记录表,这将变得更加困难。

现在,如果您想简单地捕获最后一个用户来更新或插入特定项目(表行)并且可能在多个表中,那么您可以使用继承模式,其中您有一个父表和多个子表.例如:

CREATE TABLE Audited_Items
(
    id    INT    NOT NULL    IDENTITY,
    CONSTRAINT PK_Audited_Items PRIMARY KEY CLUSTERED (id)
)
CREATE TABLE Articles
(
    id    INT            NOT NULL,
    [Article specific columns]
    CONSTRAINT PK_Articles PRIMARY KEY CLUSTERED (id),
    CONSTRAINT FK_Articles_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id)
)
CREATE TABLE Media
(
    id    INT            NOT NULL,
    [Media specific columns]
    CONSTRAINT PK_Media PRIMARY KEY CLUSTERED (id),
    CONSTRAINT FK_Media_Audited_Items FOREIGN KEY (id) REFERENCES Audited_Items (id)
)
CREATE TABLE Audit_Trail
(
    audited_item_id    INT         NOT NULL,
    audit_datetime     DATETIME    NOT NULL,
    user_id            INT         NOT NULL,
    [audit columns]
    CONSTRAINT PK_Audit_Trail PRIMARY KEY CLUSTERED (audited_item_id, audit_datetime),
    CONSTRAINT FK_Audit_Trail_Audited_Items FOREIGN KEY (audited_item_id) REFERENCES Audited_Items (id)
)

【讨论】:

  • 感谢汤姆的详细回复。我非常喜欢这个设计,并会在我的进一步研究中考虑它。
  • 结束这个问题的循环,谢谢 Tom H.,你的方法似乎很好地满足了我的设计。希望今后需要进行一些更改。
【解决方案2】:

在我看来,您是在寻求指导,引导您走上曲折的荆棘之路。

我不知道为什么每次获得一个新的“模块”(我不清楚模块是什么)时都需要添加一个新表,前提是这些模块都可以用相同的列布局来描述。您可以添加一个 Modules 表,然后在 Articles 表中包含一个 ModuleId 列。

此外,文章可以有多个作者,因此如果您有,则需要一个 ArticleAuthors 表。在某些圈子里,一篇文章的作者顺序很重要。这是对他们贡献的重要性或他们在该领域的重要性的排名。如果是这种情况,您需要有一个“序数”列来反映作者的立场。

【讨论】:

  • 感谢蒂姆的快速回复;模块代表我正在研究的 CMS 的子系统。一篇文章的多个作者可以由原作者用户代表,以及随后的作者编辑。用户按级别排名(为简单起见,我没有在示例模型中包含许多不相关的字段)我一直希望找到某种“table-ID”解决方案,它独立于模型本身......
  • 为了进一步扩展,我确实有一个 Modules 表,用于注册和注销模块(并保存配置参数等),但一个模块可能有多个表,例如带有 Track 和 Album 的 Discography。 Track 和 Album 都需要单独的 ChangeHistory 表(或公共中间表中的引用),因此单个 module_id 不足以同时引用 Track 和 Album。
【解决方案3】:

我认为最好使用一个看起来像这样的 ChangeHistory 表:

项目变更历史 +- 身份证 +- 改变Item_id +- 用户 ID +- 改变了ItemType_id +- 类型 [枚举(插入、更新、删除)] +- 日期时间

然后使用changedItemType_id 根据itemType 表找出更改的内容(例如文章、媒体等)。这样一来,所有内容更改历史记录只有一个表,并且在添加/删除模块时不必添加/删除表,只需更新itemType 表。当然,这意味着删除模块必须小心 - 您可以留下引用该模块类型的 ItemChangeHistory 记录(但这很混乱)或删除与该模块关联的所有历史记录。


现在您提到一个模块可能有其他表,所以可能需要使用子模块 ID 跟踪这些表,在 ItemChangeHistory 中也引用了?

【讨论】:

    【解决方案4】:

    为什么不

    ChangeHistory
    +- id
    +- content_id
    +- content_type
    +- user_id
    +- action [enum(added, updated, deleted)]
    +- datetime
    

    【讨论】:

      【解决方案5】:

      @马吉德: 我知道这可能是最合理的解决方案,但我希望找到一些更直观的东西,可以利用现有数据库参数的东西;例如难以捉摸(显然不存在)的表 id(我的意思是某种内部引用,在我的例子中,引擎 InnoDB 用来描述表)

      @沮丧: 我想我会选择这样的东西。我将继续调查可能性。

      【讨论】:

        猜你喜欢
        • 2012-11-16
        • 2021-04-07
        • 2011-03-14
        • 2011-07-28
        • 2014-06-28
        • 2014-06-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多