如何在外键引用字段上设置数据库完整性检查

时间:2011-03-26 15:58:26

标签: sql-server-2008 foreign-keys constraints

我有四个这样的数据库表:

  

图书
  ID_Book | ID_Company |描述

     

BookExtension
  ID_BookExtension | ID_Book | ID_Discount

     

折扣
  ID_Discount |说明| ID_Company

     

公司
  ID_Company |说明

通过外键的任何BookExtension记录间接指向两个不同的ID_Company字段:

  

BookExtension.ID_Book引用包含Book.ID_Company的Book记录   BookExtension.ID_Discount引用包含Discount.ID_Company

的折扣记录

是否可以在Sql Server中强制BookExtension中的任何新记录必须Book.ID_Company = Discount.ID_Company

简而言之,我希望以下Query必须返回0记录!

SELECT count(*) from BookExtension 
INNER JOIN Book ON BookExstension.ID_Book = Book.ID_Book
INNER JOIN Discount ON BookExstension.ID_Discount = Discount.ID_Discount
WHERE Book.ID_Company <> Discount.ID_Company

或用简单的英语:
我不希望BookExtension条记录引用Book的{​​{1}}条记录以及另一条Company的{​​{1}}条记录!

2 个答案:

答案 0 :(得分:2)

除非我误解了您的意图,否则您使用的SQL语句的一般形式是

ALTER TABLE FooExtension
ADD CONSTRAINT your-constraint-name
CHECK (ID_Foo = ID_Bar);

假设现有数据已经​​符合新约束。如果现有数据不符合,您可以修复数据(假设需要修复),或者您也可以通过检查ID_FooExtension的值来限制新约束的范围(可能)。 (假设您可以通过ID_FooExtension的值识别“新”行。)

稍后。 。

谢谢,我确实误解了你的情况。

据我所知,您不能以您希望的方式在SQL Server中强制执行该约束,因为它不允许在CHECK约束内进行SELECT查询。 (我在SQL Server 2008中可能错了。)一个常见的解决方法是将SELECT查询包装在一个函数中,并调用该函数,但根据我所学到的,这是不可靠的。

可以这样做。

  1. 在Book上创建UNIQUE约束 (ID_Book,ID_Company)。其中一部分看起来像UNIQUE (ID_Book, ID_Company)
  2. 在Discount(ID_Discount,ID_Company)上创建UNIQUE约束。
  3. 添加两列 BookExtension - Book_ID_Company和 Discount_ID_Company。
  4. 填充这些新列。
  5. 更改外键约束 在BookExtension中。你要 BookExtension(ID_Book, Book_ID_Company)来参考 书(ID_Book,ID_Company)。外键的类似变化
    引用折扣。
  6. 现在您可以添加一个检查约束,以保证BookExtension.Book_ID_Company与BookExtension.Discount_ID_Company相同。

答案 1 :(得分:2)

我不确定这会有多高效,但您也可以使用索引视图来实现这一目标。它需要一个包含2行作为CTE的帮助器表,并且在索引视图中不允许UNION

CREATE TABLE dbo.TwoNums
 (
 Num int primary key
 )

 INSERT INTO TwoNums SELECT 1 UNION ALL SELECT 2

然后是视图定义

 CREATE VIEW dbo.ConstraintView
 WITH SCHEMABINDING
 AS
    SELECT 1 AS Col FROM dbo.BookExtension 
    INNER JOIN dbo.Book ON dbo.BookExtension.ID_Book = Book.ID_Book
    INNER JOIN dbo.Discount ON dbo.BookExtension.ID_Discount = Discount.ID_Discount
    INNER JOIN dbo.TwoNums ON  Num = Num
    WHERE dbo.Book.ID_Company <> dbo.Discount.ID_Company

视图上的唯一索引

CREATE UNIQUE CLUSTERED INDEX [uix] ON [dbo].[ConstraintView]([Col] ASC)