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。

我决定用一个触发器来控制这个完整性。