Sql 主键(a,b)与主键(b,a)不同吗?
我有一个Sql 主键(a,b)与主键(b,a)不同吗?,sql,sql-server,primary-key,Sql,Sql Server,Primary Key,我有一个员工和一个主管表格。主管是雇员。employee表如下所示: employee_id | employee_name 1 | Freeman 2 | Manfred supervisor表如下所示(字段是employee表的外键): 我实现了一个复合主键(主管id、员工id),但这并没有阻止更新 如何防止上述情况发生?员工不能监督他/她的主管。当然是这样。复合键意味着您的键是两个值的对 仅当且仅当a对第一属性等于b对第一属性且a对第二属性等于b对
员工
和一个主管
表格。主管是雇员。employee
表如下所示:
employee_id | employee_name
1 | Freeman
2 | Manfred
supervisor
表如下所示(字段是employee
表的外键):
我实现了一个复合主键(主管id、员工id),但这并没有阻止更新
如何防止上述情况发生?员工不能监督他/她的主管。当然是这样。复合键意味着您的键是两个值的对 仅当且仅当a对第一属性等于b对第一属性且a对第二属性等于b对第二属性时,a对才等于b对 您需要的是一个良好的约束,而不是主键。 我要提醒你们的是,若(b,a)对已经在表中,那个么阻止插入(a,b)对的约束将无法解决你们的问题,因为监管实现的过渡
我的意思是:让a成为b的监督者,b成为c的监督者。c是否能够成为a的主管?仅凭主键或检查约束是不容易做到的
- 主键是唯一的约束,指定任何行都不能与任何其他行具有相同的主键。但它并没有说某些组合是无效的
- 检查约束可以使用更复杂的逻辑,但仅限于要插入的行中的列的值。您的问题需要查看其他行。(但请参阅Gordon Linoff的答案,了解如何使用约束实现这一点——尽管它有点不透明)
从这里开始:您可以通过两种方式来实现这一点。一种是对值的顺序施加检查约束,并使用唯一约束(或主键)。这将是:
alter table supervisor add constraint chk_supervisor_employee check (supervisor_id < employee_id);
alter table supervisor add constraint chk\u supervisor\u employee check(supervisor\u id
这就创建了功能。但它在语义上并不能满足你的需要。相反,您可以添加列以获得最小值和最大值,然后添加唯一约束:
alter table supervisor add minse (case when supervisor_id < employee_id then supervisor_id else employee_id end);
alter table supervisor add maxse (case when supervisor_id < employee_id then employee_id else supervisor_id end);
alter table supervisor add constraint unq_supervisor_employee unique(minse, maxse);
alter table supervisor add minse(当supervisor\u id
如果没有需要通知的用户界面,那么验证失败时,siride使用触发器的解决方案是一个不错的解决方案,Gordon Linoff解决方案也可以工作。一个更简单的解决方案是使用存储过程更新表,它还能够通知用户界面数据验证失败
CREATE PROCEDURE AddSupervisor
(
@supervisor_id int,
@employee_id
)
AS
INSERT INTO supervisor
SELECT @supervisor_ID, @employee_id
WHERE
NOT EXISTS
(
SELECT 1 FROM supervisor
WHERE
supervisor_id = @employee_id AND
employee_id = @supervisor_id
) AND NOT EXISTS -- EDIT - Add logic to stop inserts for employees who already have a supervisor
(
SELECT 1 FROM supervisor
WHERE
employee_id = @employee_id
)
SELECT @@ROWCOUNT
如果未插入行,则在末尾选择@@ROWCOUNT将返回0;如果插入行,则返回1。您可能会争辩说,您可以将这个答案与触发器或约束结合起来,以确保不会通过使用存储过程以外的其他东西来更新表来绕过验证
编辑:如果一个员工只能有一个主管,而不是有一个单独的主管表,那么您应该在员工表中有一个主管id列。拥有一个带有复合键的单独的Supervisor表将满足多对多关系,即监督多个员工的主管和拥有多个主管的员工
我如何确保员工只有一名主管
将employee_id作为主管表中的主键(而不是主管id和employee_id)。您需要向表中添加约束。主键不能以这种方式工作,所以请删除复合主键?@F.Hall:您仍然需要某种主键,但它无法完成您需要的所有操作。@F.Hall不,我会保留它。这种链接通常有一个复合主键,因为主管之间的链接是唯一的,完全标识行,并且应该被索引。但是,您还需要添加一个约束,以防止员工成为其主管的主管。但这允许一名员工有多个主管。。。如何确保员工只有一名主管?@F.Hall我已经更新了答案,添加了一个条款,该条款将排除已经有主管的员工的插入。相应触发器中的逻辑非常相似。a监督b和b监督c,我如何防止c监督a?@F.Hall这有点棘手。也许这会有帮助。。。。
CREATE PROCEDURE AddSupervisor
(
@supervisor_id int,
@employee_id
)
AS
INSERT INTO supervisor
SELECT @supervisor_ID, @employee_id
WHERE
NOT EXISTS
(
SELECT 1 FROM supervisor
WHERE
supervisor_id = @employee_id AND
employee_id = @supervisor_id
) AND NOT EXISTS -- EDIT - Add logic to stop inserts for employees who already have a supervisor
(
SELECT 1 FROM supervisor
WHERE
employee_id = @employee_id
)
SELECT @@ROWCOUNT