3

考慮這個例子的模式:如何在插入引用其他兩個表的第三個表時檢查兩個表之間的約束?

Customer (int CustomerId pk, ....) 

Employee (int EmployeeId pk, 
      int CustomerId references Customer.CustomerId, ....) 

WorkItem (int WorkItemId pk, 
      int CustomerId references Customer.CustomerId, 
      null int EmployeeId references Employee.EmployeeId, ....) 

基本上,三個表:

  • 一位顧客表的主鍵和一些附加列
  • 與主鍵的員工表的外鍵約束引用客戶表主鍵,表示客戶的員工。
  • 工作項目表,存儲爲客戶完成的工作,以及關於執行工作的特定員工的信息。

我的問題是。在添加新工作項目時,我如何在數據庫級別測試員工是否實際與客戶關聯。

如果例如Scott(員工)在Microsoft(客戶)工作,Jeff(員工)在StackOverflow(客戶)工作,我如何防止某人將工作項添加到數據庫中,並且客戶= Microsoft,僱員=傑夫,這是沒有道理的?

我可以使用檢查約束或外鍵嗎?還是我需要一個觸發器來手動測試它?

應該提到,我使用SQL Server 2008的

更新:我要補充一點,WorkItem.EmployeeId可以爲空。

謝謝,埃吉爾。

回答

3

組合列(CustomerId,EmployeeId)上的外鍵是否不起作用?

ALTER TABLE WorkItem 
ADD CONSTRAINT FK_Customer_Employee FOREIGN KEY (CustomerId, EmployeeId) 
    REFERENCES Employee (CustomerId, EmployeeId); 
+0

對不起,忘了提及WorkItem.EmployeeId可以爲null。以上是否仍然有效? – 2009-01-31 14:14:39

+0

嗯,不知道;我認爲有些RDBMS可以處理,其他的不能,我不知道SQL Server是否可以。如果沒有,你可以爲每個客戶定義一個「沒有人」的員工。否則就需要更復雜的CHECK條件。 – Kieron 2009-01-31 14:22:48

+0

好的謝謝。因此,當我嘗試執行上面的SQL時,出現以下錯誤消息:被引用表'Employee'中沒有與外鍵「FK_Customer_Employee」中的引用列表匹配的主鍵或候選鍵。 我的員工表中缺少什麼? – 2009-01-31 14:31:13

0

或者:

  • 使僱員柱員工的主鍵(也可能是一種自動識別),並在工作項記錄的僱員存儲爲外鍵,而不是存儲的員工和WorkItem中的客戶ID。您可以通過Employee表連接到Customer表來檢索WorkItem的Customer細節。

或者:

  • 使工作項目的僱員和客戶ID列的複合外鍵員工。

我個人喜歡第一種方法。

1

爲什麼你想讓employeeId爲null int WorkItem?也許你應該添加另一個表來避免這種特殊的怪異現象。從我所看到的最簡單的事情就是在workItem中爲employeeid添加一個唯一約束,如果這是您想要的,可能在customerId上也是唯一的。

添加跨越多個表的約束的更一般方法是定義一個始終爲空的視圖,並添加約束爲空。

2

您可能可以通過創建跨越這些表的「WITH SCHEMABINDING」視圖並強制執行各個表的集體約束來實現此目的。

1

你想在這裏建模麼?

  1. 你是一個簽約代理機構或類似的公司,並且你有一羣承包商(在某段時間內)被分配給一個客戶。

  2. 您實際上存儲有關其他公司員工的信息(例如,您可能正在提供外包工資服務)。

如果是(1),看起來您的表格有Employee問題。特別是,當斯科特與MS的合同到期並與其他人簽約時,您無法保留歷史數據,因爲您需要更改CustomerId。這也使所有WorkItem無效。相反,你應該有第四個表格,例如CustomerEmployee來存儲它。然後WorkItem應該引用該表。

如果是(2),您的員工主鍵應該是CustomerId,EmployeeId。兩個客戶可以有相同的員工ID號。然後Kieron的外鍵會起作用。

1

我最近通過了類似的情況,可以考慮的模式: 表公司(id_cia PK)表PRODUCT_GROUP(id_cia FK到公司,id_group PK)表產品(id_group FK到PRODUCT_GROUP,id_product PK,id_used_by_the_client空)

規則:數據庫必須只允許一個公司的每個產品使用一個id_used_by_the_client,但此字段可以爲空。例如:

插入公司(1)=允許

插入公司(2)=允許

插入PRODUCT_GROUP(1,1)=允許

插入PRODUCT_GROUP(1, 2)=允許

插入PRODUCT_GROUP(2,3)=允許

插入到產品中的值(1,1,空)=允許

插入到產品中的值(1,2,空)=允許

插入到產品中的值(1,3,1)=允許

插入到產品中的值(1,4,1)=不允許,在屬於公司1的組1中已存在一個id_used_by_the_client = 1。

插入產品值(2,4,1)=不允許,屬於公司1的組2中已存在一個id_used_by_the_client = 1.

插入產品值s(3,4,1)=允許,在屬於公司2的組3中沒有id_used_by_the_client = 1。

我決定用一個觸發器來控制這個完整性。