如何跨多个表强制执行CHECK约束

时间:2015-01-27 14:21:18

标签: sql-server database tsql check-constraints

我有一个数据库,可以记录Microsoft SQL Server 2012 Express中奶牛的育种信息。显然,一头母牛出生后才能繁殖,并且在她的一生中可能多次繁殖;我需要在我的数据库中强制执行这些约束。我目前根据下图安排了一个架构:

Cow Database Schema Diagram

DataID是所有动物的主要钥匙。我试图实现Table-Per-Type继承,因此[Animals].[Master][Animals].[Females]之间的一对一关系。由于每个女性可能会多次繁殖,因此我在[Animals].[Females][Breedings].[Breedings]

之间建立了一对多的关系

我的问题是:如何执行适用于所有女性的规则BirthDate< Breedings.Date

我基本上需要类似下面的psudocode(我实际上已将其置于CHECK约束的“表达式”框中并收到验证错误):

[Animals].[Master].[BirthDate] < [Breedings].[Breedings].[Date]
INNER JOIN [Animals].[Master] ON
[Breedings].[Breedings].[DataID] = [Animals].[Master].[DataID]

我也尝试使用正确的连接创建视图,但发现CHECK约束不能在视图中使用。

那么,有没有人知道如何强制执行这些约束?

编辑 - 我尝试了使用触发器的建议,但无法正确制定触发器语法。这是我的代码:

USE [CowInventory];
GO
CREATE TRIGGER [Breedings].[iCheckBreedingDateAfterBirthDate]
ON [Breedings].[Breedings]
FOR INSERT
AS
BEGIN
    DECLARE @CowID UniqueIdentifier
    SELECT @CowID = DataID FROM inserted;

    DECLARE @CowBirthDate Date
    SELECT @CowBirthDate = BirthDate FROM [Animals].[Master] WHERE [Master].[DataID] = @CowID

    DECLARE @BreedingDate Date
    SELECT @BreedingDate = Date FROM inserted;

    IF(@CowBirthDate > @BreedingDate)
        BEGIN
            THROW;
        END
END

根据我的一本书( SQL Server 2012 Step by Step ),这种语法应该完美无缺。但是,SQL Server在THROW和最后END下给了我粉红色的行,说明Incorrect syntax near 'THROW'. Expecting CONVERSATION, DIALOG, DISTRIBUTED, or TRANSACTION.Incorrect syntax near 'END'. Expecting CONVERSATION.我插入了这些关键字,但它们没有任何改变。

2 个答案:

答案 0 :(得分:3)

我不会使用触发器。使用检查约束。更清洁。请记住,检查约束可以调用函数。编写一个函数,在另一个表中进行检查。然后从检查约束中调用该函数。这是实现多表检查约束的最佳方法。

答案 1 :(得分:1)

您可以在Breedings表上创建触发器以检查此规则。触发器是一个特殊的存储过程,它在某些表上的INSERT \ UPDATE \ DELETE上自动执行。因此,您可以编写一个触发器来检查插入Breedings中的所有新行,如果有一行其中Date少于适当的BirthDate,则抛出错误。对于UPDATE也是如此,如果更改了Date列,请检查相应的动物的BirthDate并相应地抛出错误。 DELETE在这件事上是安全的。

对于涉及其他表的规则,CHECK不太好。一般建议是仅将它们用于一个表内的基本检查。

后期编辑

试试这个触发器主体

...
BEGIN
 if exists
 (
  SELECT 1
  FROM inserted i
    join Animals.Females f
      on i.DataID = f.DataID
    join Animals.Master m
      on f.DataID = m.DataID
  WHERE
    m.BirthDate > i.Date

 )
 RAISERROR("Trigger iCheckBreedingDateAfterBirthDate - Breedings.Date is wrong", 18, 0)
END
GO