【问题标题】:Database Design - Referencing a table multiple times from multiple tables数据库设计 - 从多个表中多次引用一个表
【发布时间】:2018-09-06 14:04:10
【问题描述】:

您好 stackoverflow 数据库设计专家!

我在我的数据库中遇到了一个设计问题,我在 Stackoverflow 中没有发现任何类似的问题,因此提出了这个问题。

我有一个图像表,其中包含图像数据和它的主键。在我的设计中,可以跨多个表多次引用每个图像。

这是数据库的表示:

 --------------------    -------------------------------------------
| image              |  | table1                                    |
|--------------------|  |-------------------------------------------|
| id_image | data    |  | id_table1 | id_image | data               |
|----------|---------|  |-----------|----------|--------------------|
| 1        | Image 1 |  | 1         | 1        | References image 1 |
| 2        | Image 2 |  | 2         | 3        | References image 3 |
| 3        | Image 3 |   -------------------------------------------
 --------------------
 -------------------------------------------
| table2                                    |
|-------------------------------------------|
| id_table2 | id_image | data               |
|-----------|----------|--------------------|
| 1         | 2        | References image 2 |
| 2         | 2        | References image 2 |
| 3         | 3        | References image 3 |
 -------------------------------------------

以下是表格详情:

  • 图片表
    • id_image 自增主键
    • 数据图片数据
  • table1 表格
    • id_table1 自增主键
    • id_image 外键引用 image.id_image
    • 数据 table1 数据
  • table2 表格
    • id_table2 自增主键
    • id_image 外键引用 image.id_image
    • 数据 table2 数据

我希望我的数据库表现如下:

  • 如果我删除带有id_table1 = 1table1 行,则必须删除带有id_image = 1 的图像行(没有其他对该图像的引用)
  • 如果我随后删除带有id_table2 = 1table2 行,则不应删除任何图像(因为带有id_image = 2 的图像仍被带有id_table2 = 2table2 行引用)
  • 如果我随后删除带有id_table2 = 2table2 行,则必须删除带有id_image = 2 的图像行(没有其他对该图像的引用)
  • 如果我随后删除带有id_table1 = 2table1 行,则不应删除任何图像(因为带有id_image = 3 的图像仍被带有id_table2 = 3table2 行引用)
  • 如果我随后删除带有id_table2 = 3table2 行,则必须删除带有id_image = 3 的图像行(没有其他对该图像的引用)

我已经尝试了一些级联删除,通过反转外键(即包含 id_table1id_table2 外键的 image 表),但如果在其他 2 个表中引用图像,则删除一个引用表条目还会删除图像,这是我不希望发生的。

我也尝试定义触发器,但这种方法比我想象的要复杂:每次我都必须检查id_image 的所有外键,看看是否有另一个要删除的图像引用。此示例包含 2 个外键,但在我正在设计的数据库中将有超过 10 个...

我觉得这个简单的问题有一个简单的解决方案,有人来帮助我吗?

谢谢!

【问题讨论】:

  • 当其他两个表中的任何一个都没有 id 时,您想从图像中删除(通过触发器)。用它们和图像之间的 id 并集制作一个表格。
  • 刚写完我的回答,看了你的评论,感觉我找到的解决方案和你的建议很接近!
  • 不需要代理列。 (通常情况下,id_tableN 映射到只映射回它的代理。请注意,不仅代理是表 1 和表 2 中的 FK,而且 (idN,proxy) 是 FK。不需要代理。) (你为什么把它们放进去?你认为每张桌子都需要一个替代品吗?)删除它们给出了我的建议。 FK 说,子行值必须以 PK 或 UNIQUE NOT NULL 的形式出现在另一个特定位置。这就是正在发生的一切。 PS 你有两个 子类型 图像,1 和 2。Google re sql/database subtying/inheritance。这是常见问题解答,尽管您是在询问更新算法。
  • 这个代理表是为了简化我的触发器。没有它,我必须检查所有引用图像的表,看看是否仍然存在对受删除影响的图像的引用。如果我添加另一个引用图像的表,我必须更新所有现有触发器以检查这个新表......也许我在这里遗漏了一些东西,请随时在答案中详细说明您的建议!

标签: sql-server database database-design triggers foreign-keys


【解决方案1】:

马上因为你的第一个要求:

如果我删除 id_table1 = 1 的 table1 行,图像行 id_image = 1 必须删除(没有其他对该图像的引用)

我可以告诉您,您只能通过触发器来完成此操作。原因是您希望在从 Child 表中删除一行时自动从 Parent 表中删除。

反向(删除父级时删除子级)可以使用级联外键完成,但不能这样做。

您需要在两个子表上放置触发器以强制执行您想要的逻辑。

【讨论】:

  • 是的,但是使用这种设计,触发器将很难定义,正如我在问题中所说的那样。我宁愿使用其他设计,但我想不出更好的设计......
  • 不幸的是,我没有告诉你触发器是一种选择。我告诉你,他们是你唯一的选择。当然,它们需要一些复杂的编码,但这是您要求的代价,抱歉。
【解决方案2】:

我昨天想出了一个更好的设计。它仍然使用触发器(如Tab Alleman said),但定义起来要简单得多:

 --------------------    ---------------------------
| image              |  | image_proxy               |
|--------------------|  |---------------------------|
| id_image | data    |  | id_image_proxy | id_image |
|----------|---------|  |----------------|----------|
| 1        | Image 1 |  | 1              | 1        |
| 2        | Image 2 |  | 2              | 3        |
| 3        | Image 3 |  | 3              | 2        |
 --------------------   | 4              | 2        |
                        | 5              | 3        |
                         ---------------------------

 -------------------------------------------------
| table1                                          |
|-------------------------------------------------|
| id_table1 | id_image_proxy | data               |
|-----------|----------------|--------------------|
| 1         | 1              | References image 1 |
| 3         | 2              | References image 3 |
 -------------------------------------------------

 -------------------------------------------------
| table2                                          |
|-------------------------------------------------|
| id_table2 | id_image_proxy | data               |
|-----------|----------------|--------------------|
| 1         | 3              | References image 2 |
| 2         | 4              | References image 2 |
| 3         | 5              | References image 3 |
 -------------------------------------------------

正如您在上面的架构中看到的,我引入了一个新表:image_proxy

  • id_image_proxy 自增主键
  • id_image 外键引用 image.id_image

另外,table1table2 现在引用 image_proxy 条目而不是 image 条目。

有了这个设计,触发器现在是:

  • 删除table1中的条目后,删除image_proxy中的对应条目。
  • 删除table2中的条目后,删除image_proxy中的对应条目。
  • 删除image_proxy 中的条目后,删除imageimage_proxy 中不再引用的条目。

我不知道这个设计是否最适合这个问题,也不知道触发器的使用是否安全,所以如果有更好的答案或相关评论,我会密切关注这篇文章!

【讨论】:

  • 你可以使用回调来代替触发器吗?销毁记录时调用的东西(提交后)。从代码中维护这些东西更容易。
猜你喜欢
  • 2014-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-04-02
  • 1970-01-01
  • 2010-11-13
  • 1970-01-01
相关资源
最近更新 更多