数据库设计-从多个表中多次引用一个表

时间:2018-09-06 14:04:10

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

您好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 自动递增的主键
    • 引用image.id_image
    • id_image 外键
    • 数据表1数据
  • table2表
    • id_table2 自动递增的主键
    • 引用image.id_image
    • id_image 外键
    • 数据表2数据

我希望数据库的行为如下:

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

我已经通过反转外键(即包含id_table2 = 3table2外键的id_table2 = 3表来尝试级联删除),但是如果另外2个引用了图像表,删除一个引用的表条目也会删除图像,我不想发生这种情况。

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

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

谢谢!

2 个答案:

答案 0 :(得分:0)

因为您的第一个要求,马上走

  

如果删除id_table1 = 1的table1行,则使用   id_image = 1必须删除(对此图像无其他引用)

我可以告诉您,您只能使用TRIGGER来完成此操作。原因是因为您要在从子表中删除一行时自动从父表中删除。

可以通过级联外键完成相反的操作(删除父级时删除子级),但不能这样做。

您将需要在两个子表上都放置触发器,以实施所需的逻辑。

答案 1 :(得分:0)

昨天我想出了一个更好的设计。它仍然使用触发器(如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 自动递增的主键
  • 引用image.id_image
  • id_image 外键

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

通过这种设计,触发器现在是:

  • 删除table1中的条目后,删除image_proxy中的相应条目。
  • 删除table2中的条目后,删除image_proxy中的相应条目。
  • 在删除image_proxy中的条目之后,删除image中不再引用的image_proxy中的条目。

我不知道这种设计是否最适合该问题,也不知道触发器的使用是否安全,这就是为什么如果有更好的答案或相关评论,我将密切关注这篇文章!