在插入引用其他两个表的第三个表时,如何检查两个表之间的约束?

时间:2009-01-31 13:58:44

标签: sql sql-server database-design foreign-keys check-constraints

考虑这个示例模式:

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(客户)工作,我如何阻止某人将工作项添加到数据库中,customer = Microsoft和employee杰夫,这没有意义吗?

我可以使用检查约束或外键来执行此操作,还是需要触发器来手动测试?

应该提到我使用的是SQL Server 2008。

更新:我应该补充一点,WorkItem.EmployeeId可以为null。

谢谢,Egil。

6 个答案:

答案 0 :(得分:3)

复合列(CustomerId,EmployeeId)上的外键是否有效?

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

答案 1 :(得分:2)

您可以通过创建跨越这些表的“WITH SCHEMABINDING”视图并强制执行各个表的集合约束来实现此目的。

答案 2 :(得分:1)

为什么您希望employeeId为null int WorkItem?也许你应该添加另一个表来避免这种特殊的怪异。从我可以看到的最简单的事情是在workItem中为employeeid添加一个唯一约束,如果这是你想要的,甚至可能在customerId上是唯一的。

添加跨越多个表的约束的更一般方法是定义一个应该始终为空的视图,并添加它为空的约束。

答案 3 :(得分:1)

你想在这里建模什么?

  1. 您是一个承包代理商或类似机构,并且您有一堆承包商(在一段时间内)分配给客户。

  2. 您实际上存储的是有关其他公司员工的信息(例如,您可能提供外包工资单服务)。

  3. 在案例(1)中,您似乎遇到了Employee表的问题。特别是,当Scott与MS签订合同并且与其他人签订合同时,您无法保留历史数据,因为您需要更改CustomerId。这也使所有WorkItem无效。相反,您应该有第四个表格,例如CustomerEmployee来存储它。然后WorkItem应该引用该表。

    在案例(2)中,您在Employee上的主键应该是CustomerIdEmployeeId。两个客户可以拥有相同的员工ID号。然后Kieron的外键将起作用。

答案 4 :(得分:1)

我最近传递到类似的情况,考虑架构: 表公司(id_cia PK)表product_group(id_cia FK to company,id_group PK)表产品(id_group FK to product_group,id_product PK,id_used_by_the_client null)

规则:数据库必须只允许公司的每个产品使用一个id_used_by_the_client,但此字段可以为null。例如:

插入公司(1)=允许

插入公司(2)=允许

插入product_group(1,1)=允许

插入product_group(1,2)=允许

插入product_group(2,3)=允许

插入产品值(1,1,null)=允许

插入产品值(1,2,null)=允许

插入产品值(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.

插入产品中的值(3,4,1)=允许,在属于公司2的第3组中,没有id_used_by_the_client = 1。

我决定使用触发器来控制这种完整性。

答案 5 :(得分:0)

要么:

  • 将EmployeeID列设置为Employee的主键(可能还有auto-id),并将EmployeeID作为外键存储在WorkItem记录中,而不是将Workee和Customer ID存储在WorkItem中。您可以通过Employee表连接到Customer表来检索WorkItem的客户详细信息。

或者:

  • 将WorkItem的EmployeeID和CustomerID列作为Employee的复合外键。

我个人赞成第一种方法。