如何在检查约束中引用其他表?

时间:2011-03-20 23:53:35

标签: sql-server referential-integrity check-constraints

我有一张表,ProductSupportArticles:

ProductSupportArticleID int NOT NULL <primary key>
ParentArticleID int NULL
ProductID int NOT NULL
Title varchar(100) NOT NULL
Content varchar(MAX) NOT NULL

ProductID是Products.ID的外键,ParentArticleID是同一个表的外键,ProductSupportArticles.ProductSupportArticleID。我有一个检查约束ProductSupportArticleID!= ParentArticleID,以便文章不能是它自己的父。

但是,与特定产品相关的支持文章不应该是与不同产品相关的文章的父母或子女。如何添加检查约束或类似说法:(ProductID = (SELECT ProductID FROM ProductSupportArticles P WHERE ParentArticleID = P.ProductSupportArticleID))

或者我应该如何以不同的方式实现我的表?

2 个答案:

答案 0 :(得分:5)

  1. 在(ProductSupportArticleID,ProductID)上创建UNIQUE约束。
  2. 将FK引用(ParentArticleID,ProductID)指向(ProductSupportArticleID,ProductID)
  3. 警告:通过包含在CHECK约束中的UDF实施业务规则存在多个漏洞。例如,它们可能会给多行修改带来误报和漏报。他们也很慢。

答案 1 :(得分:2)

工作样本

示例表:

create table products (productid int primary key)
insert products select 1
insert products select 2
GO

create table ProductSupportArticles (
ProductSupportArticleID int NOT NULL primary key,
ParentArticleID int NULL references ProductSupportArticles(ProductSupportArticleID),
ProductID int NOT NULL references products (productid),
Title varchar(100) NOT NULL,
Content varchar(MAX) NOT NULL
)
GO

支持功能

create function dbo.getProductSupportArticleParent(@ParentArticleID int)
returns int
with returns null on null input
as
begin
return (select ProductID from ProductSupportArticles where ProductSupportArticleID = @ParentArticleID)
end
GO

约束

alter table ProductSupportArticles add check(
    ParentArticleID is null or
    dbo.getProductSupportArticleParent(ParentArticleID) = ProductID)
GO

测试

insert ProductSupportArticles select 1,null,1,3,4
insert ProductSupportArticles select 2,null,1,3,4
insert ProductSupportArticles select 3,null,2,3,4
insert ProductSupportArticles select 4,1,1,3,4

好了到目前为止,下一个打破它,因为5是1的父级,属于产品1。

insert ProductSupportArticles select 5,1,2,3,4

<小时/>

修改

Alex指出了一个有效的缺陷。为了覆盖这种情况,您需要一个UPDATE触发器,它将对记录的ProductID的更改传播到所有子(和后代)记录。这将是一个简单的触发器,所以我不会在这里提供代码。