使用循环外键在表上添加约束

时间:2014-01-15 03:04:24

标签: sql sql-server foreign-keys constraints

我们的系统中有用户连接了联系人。因此,我们通过在联系人表中使用外键来实现此目的,该外键指向用户表中的拥有用户。但现在我们需要添加要求用户拥有默认联系人的功能。所以我为用户的默认联系人添加了一列,指向联系人表作为外键。请注意下表。

这两张桌子(我把它们砍成了相关的栏目):

users table:
      user_id varchar(20) PK
      default_contact bigint FK to contacts.id (nullable)

contacts table:
      id bigint PK
      user_id varchar(20) FK to users.user_id

注意圆形外键。

现在我想向users表添加一个约束,该约束表明default_contact只能是属于该用户的联系人(即联系人的user_id ==将其作为默认联系人的用户的user_id) 。我现在卡住了因为我不确定如何添加这个约束。这可能可以通过断言来解决,但是因为我使用SqlServer断言不受支持。这一定是一个常见的问题,因为这是两天内第二次在两个完全不同的情况下遇到类似情况。

甚至可以添加这个约束?如果是这样,我将如何这样做?


编辑 - 2014年1月15日03:39 UTC

所以我找到了一种方法可以做到这一点,即在存储过程中通过检查添加约束。只要我们总是通过存储过程访问users.default_contact字段,这将有效,但我想知道是否还有其他严格的解决方案。

1 个答案:

答案 0 :(得分:2)

SQL Server中,您可以使用多种技术来实现这一目标。一个常见的方法是使用Check ConstraintsUser-Defined Functions的组合。这样,当您将约束添加到users表时,每次执行INSERTUPDATE语句时,约束都将验证为默认联系人指定的值。

首先,您需要创建函数...

create function ValidateContact(@userid int, @contact int)
returns bit
as
begin
   declare @count int,
           @retVal bit;

   select @count = count(*) from dbo.contacts where user_id = @userid and id = @contact

   if @count = 0 and @contact is not null
    set @retVal =  0;
    else
    set @retVal =  1;

   return @retVal;
end
go

此功能将接收两个参数(用户ID和联系人),然后检查用户是否存在联系人。如果没有,则返回0(false),否则返回1(true)。您需要创建CHECk约束...

alter table dbo.users
add constraint chk_default_contact 
check (dbo.ValidateContact(user_id, default_contact) = 1)
go

现在,每次执行INSERTUPDATE语句时,CHECK约束将根据ValidateContact函数中指定的逻辑验证输入,如果验证失败,抛出错误并中止事务。

希望有所帮助