代码之家  ›  专栏  ›  技术社区  ›  Dan Lugg mab

数据库表,一个表引用多个不相关的表

  •  5
  • Dan Lugg mab  · 技术社区  · 15 年前

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

    如果我有下表:

    User
    +- id
    +- username
    +- password
    
    Article
    +- id
    +- title
    +- content
    

    为了确定谁创建了什么文章,我想加入他们,只需添加这个列 用户标识 文章 用作参考。或者,我要添加一个中间表来显示谁/何时/什么,例如:

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

    现在这很好,但是我正在研究的系统需要更加动态,因为新的模块可以很容易地引入和集成。所以现在如果我加一个 媒体 表我需要拆分 变化历史 之间 文章 媒体

    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
    

    5 回复  |  直到 15 年前
        1
  •  4
  •   Tom H zenazn    15 年前

    根据我的经验,当开发人员试图使他们的系统真正“动态”时,他们实际上是在为他们还没有想到的问题编写代码。这通常是一条不好的路。一个模块包含两个表而不是一个表真的有那么多额外的工作吗?

    在任何情况下,我都看到了模式(或反模式?)为了制作一张普通的“万事俱备”的桌子,它的脸被压扁了。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)
    )
    
        2
  •  2
  •   Tim    15 年前

    在我看来,你是在找一个向导带领你走一条弯弯曲曲、荆棘丛生的小路。

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

    另外,文章可以有多个作者,所以如果有,您需要一个ArticleAuthors表。在某些圈子里,作者对一篇文章的顺序很重要。这是他们贡献的重要性或他们在这个领域的重要性的排名。如果是这样,您需要有一个“序数”列来反映作者的位置。

        3
  •  2
  •   FrustratedWithFormsDesigner    15 年前

    我认为您最好使用一个changeHistory表,该表如下所示:

    ItemChangeHistory
    +- id
    +- changedItem_id
    +- user_id
    +- changedItemType_id
    +- type [enum(insert, update, delete)]
    +- datetime
    

    然后使用 changedItemType_id 根据 itemType 表。这样,对于所有内容更改历史记录,您只有一个表,并且在添加/删除模块时不必添加/删除表,只需更新 项目类型 表。当然,这意味着要小心地移除模块-您可以将 ItemChangeHistory 记录引用该模块的类型(但这很混乱)或删除与该模块关联的所有历史记录。


    现在您提到一个模块可能有其他表,所以可能需要使用子模块ID跟踪这些表,也可以在 项目更改历史记录 ?

        4
  •  0
  •   Majid Fouladpour    15 年前

    为什么不呢?

    ChangeHistory
    +- id
    +- content_id
    +- content_type
    +- user_id
    +- action [enum(added, updated, deleted)]
    +- datetime
    
        5
  •  0
  •   Dan Lugg mab    15 年前

    @ Majid: 我理解这可能是最合理的解决方案,但我希望找到一些更直观的解决方案,一些可能利用现有数据库参数的方案,例如难以捉摸(而且显然不存在)的表ID(我指的是引擎innodb在我的例子中用来描述TA的某种内部引用)。BLE)

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

    推荐文章