当两个 FK 列需要在同一个表中匹配自己时的参照完整性?

use*_*679 2 foreign-key database-design sql-server referential-integrity

可能我的设计是错误的,或者只是有更好的方法。我将使用一个非常简单的例子:

    --------- dbo.Book----------
   |                            |
   |  BookID int identity (1,1) |
   |  ShelfID int FK            |--
    ----------------------------   |
                                   |
    --------- dbo.Row-----------   |    
   |                            |  |    
 --|  RowID int identity (1,1)  |  |    
|   ----------------------------   |    
|                                  |        
|   -------- dbo.Shelf----------   | 
|  |                            |  |
|  |  ShelfID int identity (1,1)|--
 --|  RowID int FK              |
    ----------------------------
Run Code Online (Sandbox Code Playgroud)

足够简单。

但是如果我想分配一个没有架子的行怎么办?也许我们还知道行而不是货架:

    --------- dbo.Book----------
   |                            |
   |  BookID int identity (1,1) |
   |  RowID int FK              | <-- New
   |  ShelfID int FK NULL       | 
    ---------------------------- 
Run Code Online (Sandbox Code Playgroud)

有没有更好的设计方法呢?我需要确保ShelfIDRowID自己各自的父/子表匹配。

最好的方法是什么?调用函数的约束?好像很贵 不同的表结构?我可能会遗漏一些非常简单明显的东西。

细化:

如果dbo.Shelf具有以下值:

[ShelfID]  [RowID]
------------------
 3          1
Run Code Online (Sandbox Code Playgroud)

然后我们应该期望该dbo.Row表具有一个值为 1 的主键。我希望该表具有相同的参照完整性dbo.Book

[BookID] [RowID] [ShelfID]
--------------------------
1        1       3
Run Code Online (Sandbox Code Playgroud)

我该如何强制执行?称为约束的函数是最好的方法吗?还是我的设计有问题?

如果Book表中存在两个值,我的要求是维护数据完整性。其他两个表中必须存在相关关系。也许我把它复杂化了,调用函数的检查约束是要走的路。

我知道能够将 FK 设置为 null。基本上,如果ShelfIDRowID两者在主Book表中都有一个值,那么确保它RowIDShelfID匹配的最佳方法是什么?ShelfID必须存在于dbo.Shelf表中,那一个很容易。但是RowIDinBook表必须是在dbo.Shelf.

确保 aShelfIDRowID不要最终出现在Book虚假关系表中的最佳方法是什么?例如 ,RowID = 1ShelfID = 3,但是在Shelf表中,没有这样的关系。

ype*_*eᵀᴹ 5

你需要两件事:

  • Book该引用中添加一个额外的外键Row

  • 从修改外键Book,以Shelf使它包含RowID并成为一个外键:(RowID, ShelfID) REFERENCES Shelf (RowID, ShelfID)。这是为了对齐 2 个外键。否则,您最终可能会得到一个Bookthat 引用RowID = 1ShelfID = 33而 whileShelf 33正在引用RowID = 2.

  • 此外 - 要使上述修改成功 - 您需要UNIQUE在 Shelf 上添加约束(RowID, ShelfID)。或者,您可以修改Shelf主键。

    除了Book.ShelfID. 有一种方法可以让所有列不为空,但它需要一个额外的表。

表变成:

        --------- dbo.Row-----------    
       |                            |         
     --|  RowID int   PK            |-----    
    |   ----------------------------      ^   
    ^                                     |  
    |                                     |        
    |   -------- dbo.Shelf----------      ^ 
    ^  |                            |--   |
  FK|  |  ShelfID int PK     UQ1    |  |  |
     --|  RowID int      FK  UQ1    |  |  ^
        ----------------------------   ^  |
                                       |  |
                                    FK1|  ^
        --------- dbo.Book----------   ^  |
       |                            |--|  |
       |  BookID int  PK            |     ^FK2
       |  RowID int      FK1 FK2    |-----|
       |  ShelfID int    FK1        |
        ----------------------------   
Run Code Online (Sandbox Code Playgroud)