Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/85.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 主键(a,b)与主键(b,a)不同吗?_Sql_Sql Server_Primary Key - Fatal编程技术网

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