【问题标题】:Table must receive foreign key?表必须接收外键?
【发布时间】:2012-04-30 22:59:29
【问题描述】:

这是一个简单的问题,但我想我总是用错了方法。

我有三个名为 Page -> Tag -> Attribute 的表。 Tag 表接收 Page_Id(外键),Attribute 表接收 Tag_Id(外键)。

属性表也必须接收 Page_Id?

我从来没有这样做过,但是我看到了一个数据库 SQL 生成器可以做到这一点,所以我意识到这会让所有工作变得更容易,但这也是正确的方法吗?


使用表格的详细信息进行编辑: Page 表格包含 HTML 页面和一些属性,例如内容、标题、文档类型和 html 页面的所有其他单个元素。

Tag 表包含 html 页面的 HTML 标签,其中包含标签(a、p、br、h1、标题等)和整个标签等信息。

属性表包含一个标签的所有属性,就像一个有键和值的地图,其中每个条目是一个属性和一个值。

页面包含多个标签 (1:N),标签包含多个属性 (1:N)。每个表都包含一个唯一标识。

【问题讨论】:

  • 我想我有一些相关的东西要在这里添加,但我想在我开始之前更好地了解你的表结构。你能编辑你的问题并包括表结构和示例数据吗?
  • @Catcall 我用有关表格的更多详细信息编辑了我的问题。
  • 谢谢,但这对我没有帮助。在我开始之前,我宁愿先看看表结构本身 (SQL DDL),包括它们的主键和外键——而不是表结构的描述。几行示例数据也会有所帮助。跨度>

标签: database normalization rdbms


【解决方案1】:

这是“视情况而定”的情况之一 - 逻辑上您不需要将值存储在 Attribute 中,因为您可以通过加入 Tag 来获取此信息.

但是,在某些情况下,有用让您能够从Attribute“跳转”到Page,而无需加入Tag。在这种情况下,您可以在Attribute 中包含Page_Id,但您应该添加额外的约束以确保它与Tag 中存储的值不不一致。


您可以通过在Tag 中声明两个键来强制实现这种一致性——您定义的常用键(例如Tag_Id)以及Tag_IdPage_Id 上的超级键。然后,您将在 Attribute 中声明一个包含 both 列的外键约束,并引用此超键。您是否这样做而不是仅对Tag_Id 进行外键约束,或者除此之外,也可能是偏好/风格的问题。


如果Tags 可能会更改Pages,那么您通常会将超级键的外键声明为出现UPDATE CASCADE 的外键 - 这样,如果Page_Id 更改在Tag 表中,该更改将自动应用到Attribute 表中。

【讨论】:

  • 我认为你错了。如果没有 page_id 作为“最后”表中键的​​一部分,我认为您无法将 OPs 结构规范化为 5NF。但如果你能告诉我我的答案哪里出错了,我会很高兴。
  • @Catcall - 我在编辑之前回答了,我只是在阅读它。我仍然不确定每个页面上的标签是否是唯一的(因此您的表 A 的初始图表将标签 1 与页面 1 和 2 都关联起来是不正确的) - 据我了解,每个属性都属于一个标签,每个标签都属于一个页面。
  • 在简单的 HTML 中,标签在每个页面上并不是唯一的。 (我有很多带有

    标记的页面。)页面上的

    标记可以使用 固定集 属性的不同属性。所以在一个页面上,我可能有一些没有属性的

    标签,一些有“class”属性,一些有“id”属性,等等。在简单的 HTML 中,属性不决定标签;大多数标签可以具有类属性、id 属性等。 (我不完全确定这就是 OP 的意思。但我认为是。)

  • @Catcall - 但是 OPs 中的措辞问题是标签表同时包含“标签”和“整个标签”,这对我来说意味着“第三个 @”有两个单独的行页面p标签上的987654342@”和“页面x上的第四个p标签”。
  • 是的,我认为我对键进行了建模。想象一下我的示例数据的前两行是“第 x 页上的第 3 个 p 标签”,后两行是“第 x 页上的第 4 个 p 标签”。如果我包含一个“整个标签”属性,它将最终出现在 Table_C 或另一个表中。但这不会影响 page_id 是否最终成为该“属性”表中键的​​一部分,这就是我试图关注的内容。
【解决方案2】:

没有必要,如果您严格规范化,那么答案应该是“page_id 不应该在表属性上”。但通常需要(用于报告或只是加快某些操作)对表进行反规范化,例如在表上添加一个字段,您可以通过简单的查询(如您的示例中)获得该字段。

【讨论】:

    【解决方案3】:

    我还没有看到你的表结构,所以我必须继续你的描述。这总是有风险的。

    如果您的描述意味着页面和标签之间存在 1:M 关系,并且标签和属性之间存在 1:M 关系,那么起始关系的示例数据应该类似于下表。 (起始关系总是包含所有表的所有属性。)我假设

    • page_id 应该是标识一个页面,
    • tag_id 应该是标识一个标签,而
    • 标签的属性取决于该标签出现的页面。 (所以标签和属性之间没有多值依赖。)

      Table_A
      page_id  page_name  tag_id  tag_name  attr_id
      --
      1        page1      1       tag1      attr1
      1        page1      1       tag1      attr2
      1        page1      2       tag2      attr1
      1        page1      2       tag2      attr3
      2        page2      1       tag1      attr1
      2        page2      1       tag1      attr2
      2        page2      2       tag2      attr1
      2        page2      2       tag2      attr2
      

    我们已经从您的描述中知道 page_id -> page_name 和 tag_id -> tag_name。 (除非你想伤害自己,page_name -> page_id 和 tag_name -> tag_id 也是如此。)所以让我们根据这些知识投影新表。

    Table_C
    tag_id  tag_name
    --
    1       tag1
    2       tag2
    
    Table_B
    page_id  page_name
    --
    1        page1
    2        page2
    
    Table_A
    page_id  tag_id  attr_id
    --
    1        1       attr1
    1        1       attr2
    1        2       attr1
    1        2       attr3
    2        1       attr1
    2        1       attr2
    2        2       attr1
    2        2       attr2
    

    Table_A 中保留了哪些函数、多值或连接依赖项?没有了。唯一的候选键是 {page_id, tag_id, attr_id}。我很确定这三个表都至少在 5NF 中。

    因此,如果您对起始表进行规范化,您最终会在“最后一个”表中获得 page_id。 (顺便说一句,它不再是一个真正的属性表了,是吗?)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 2014-09-11
      • 2011-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多