当插入引用其他两个表的第三个表时,如何检查两个表之间的约束?
考虑这个示例架构:
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,员工 = Jeff,哪些没有意义?
我可以使用检查约束或外键来完成此操作,还是需要触发器来手动测试它?
应该提到我使用 SQL Server 2008。
更新:我应该补充一点,WorkItem.EmployeeId 可以为 null。
谢谢,埃吉尔。
Consider this example schema:
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, .... )
Basically, three tables:
- A customer table with a primary key and some additional columns
- A employee table with a primary key, a foreign key constraint reference to the customer tables primary key, representing an employee of the customer.
- A work item table, which stores work done for the customer, and also info about the specific employee who the work was performed for.
My question is. How do I, on a database level, test if an employee is actually associated with a customer, when adding new work items.
If for example Scott (employee) works at Microsoft (customer), and Jeff (employee) works at StackOverflow (customer), how do I prevent somebody from adding a work item into the database, with customer = Microsoft, and employee = Jeff, which do not make sense?
Can I do it with check constraints or foreign keys or do I need a trigger to test for it manually?
Should mention that I use SQL Server 2008.
UPDATE: I should add that WorkItem.EmployeeId can be null.
Thanks, Egil.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
复合列(CustomerId、EmployeeId)上的外键不起作用吗?
Wouldn't a foreign key on a composite column (CustomerId, EmployeeId) work?
您可以通过创建一个视图“WITH SCHEMABINDING”来实现此目的,该视图跨越这些表并强制执行各个表的集体约束。
You might be able to do this by creating a view "WITH SCHEMABINDING" that spans those tables and enforces the collective constraints of the individual tables.
为什么你希望employeeId为null int WorkItem? 也许您应该添加另一个表以避免这种特殊的奇怪现象。 据我所知,最简单的方法是在 workItem 中添加对 employeeid 的唯一约束,如果您想要的话,甚至可以在 customerId 上添加唯一的约束。
添加跨多个表的约束的更通用方法是定义一个应始终为空的视图,并添加它为空的约束。
Why do you want employeeId to be null int WorkItem? Maybe you should add another table to avoid that particular oddity. From what I can see the easiest thing to do is to add a unique constraint on employeeid in workItem, and maybe even unique on customerId if that is what you want.
A more general way to add constraints spanning many tables is to define a view that should always be empty, and add the constraint that it is empty.
你想在这里建模什么?
您是一家承包机构或类似机构,并且您有一群承包商(在一段时间内)分配给客户。
您实际上正在存储有关其他公司员工的信息(例如,您可能正在提供外包薪资服务)。
您实际上正在存储有关
在情况 (1) 中,
Employee
表似乎存在问题。 特别是,当 Scott 与 MS 的合同到期并且他与其他人签约时,您无法保留历史数据,因为您需要更改CustomerId
。 这也会使所有WorkItem
无效。 相反,您应该有第四个表(例如CustomerEmployee
)来存储它。 然后WorkItem
应该引用该表。在情况 (2) 中,Employee 的主键实际上应该是
CustomerId
、EmployeeId
。 两个客户可以拥有相同的员工 ID 号。 然后 Kieron 的外键就可以工作了。What are you trying to model here?
You're a contracting agency or the like, and you have a bunch of contractors who are (for some period of time) assigned to a customer.
You're actually storing information about other company's employees (maybe you're providing outsources payroll services, for example).
In case (1), it looks like you have a problem with the
Employee
table. In particular, when Scott's contract with MS is up and he gets contracted to someone else, you can't keep the historical data, because you need to change theCustomerId
. Which also invalidates all theWorkItem
s. Instead, you should have a fourth table, e.g.,CustomerEmployee
to store that. ThenWorkItem
should reference that table.In case (2), your primary key on Employee should really be
CustomerId
,EmployeeId
. Two customers could have the same employee ID number. Then Kieron's foreign key will work.我最近遇到了类似的情况,考虑一下架构:
表company (id_cia PK) 表product_group (id_cia FK to company, id_group PK) 表products (id_group FK to Product_group, id_product PK, id_used_by_the_client null)
规则:数据库必须只允许一个公司的每个产品有一个id_used_by_the_client,但该字段可以为空。 示例:
插入公司 (1) = 允许
插入公司 (2) = 允许
插入产品组 (1, 1) = 允许
插入产品组 (1,2) = 允许
插入产品组 (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。
我决定使用触发器来控制这种完整性。
I recently pass to a similar situation, consider the schema:
Table company (id_cia PK) Table product_group (id_cia FK to company, id_group PK) Table products (id_group FK to product_group, id_product PK, id_used_by_the_client null)
Rule: The database must allow only one id_used_by_the_client for each product of a company but this filed can be null. Example:
Insert into company (1) = allowed
Insert into company (2) = allowed
Insert into product_group (1, 1) = allowed
Insert into product_group (1,2) = allowed
Insert into product_group (2,3) = allowed
Insert into products values (1, 1, null) = allowed
Insert into products values (1, 2, null) = allowed
Insert into products values (1, 3, 1) = allowed
Insert into products values (1, 4, 1) = not allowed, in the group 1 that belongs to company 1 already exists an id_used_by_the_client = 1.
Insert into products values (2, 4, 1) = not allowed, in the group 2 that belongs to company 1 already exists an id_used_by_the_client = 1.
Insert into products values (3, 4, 1) = allowed, in the group 3 that belongs to company 2 there is no id_used_by_the_client = 1.
I decided to use a trigger to control this integrity.
或者:
或者:
我个人赞成第一种方法。
Either:
Or:
I favour the first approach, personally.