【问题标题】:SQL Server 2012 CHECK constraint not firing on UPDATE or DELETE statementsSQL Server 2012 CHECK 约束未在 UPDATE 或 DELETE 语句上触发
【发布时间】:2013-08-23 15:46:31
【问题描述】:

我正在尝试对表执行数据验证,我需要检查多个行和列。基本上,我想确保对于任何给定的工具,至少存在一个标记为 Active 版本或 Beta 版本的版本。

我认为检查这一点的唯一方法是通过用户定义的标量函数和调用该函数的CHECK 约束。我能够创建返回我期望的函数(如果正常,则为 0,如果不正常,则为 1)并且它可以工作......但 INSERT 上。当我执行UPDATEDELETE 语句时,检查约束不会失败,因此在任何一种情况下我都会得到错误的数据。

这是我正在使用的表格和函数的示例。

CREATE TABLE VersionTest(VersionID int NOT NULL, ToolID int NOT NULL, IsActiveVersion bit NOT NULL, IsBetaVersion bit NOT NULL)
GO

ALTER TABLE VersionTest ADD  CONSTRAINT [DF_VersionTest_IsActiveVersion]  DEFAULT ((0)) FOR [IsActiveVersion]
GO

ALTER TABLE VersionTest ADD  CONSTRAINT [DF_VersionTest_IsBetaVersion]  DEFAULT ((0)) FOR [IsBetaVersion]
GO

CREATE FUNCTION fn_ValidateVersionTest(@toolID int) RETURNS SMALLINT
AS
      BEGIN
      IF (@toolID = -1)
        BEGIN
          RETURN 0
        END
      ELSE
        BEGIN
            IF EXISTS (SELECT 1
                       FROM VersionTest
                       WHERE ToolID = @toolID
                       GROUP BY ToolID, IsActiveVersion, IsBetaVersion
                       HAVING (SUM(CASE WHEN IsActiveVersion = 1 THEN 1 ELSE 0 END) + 
                               SUM(CASE WHEN IsBetaVersion = 1 THEN 1 ELSE 0 END)) > 0)
              RETURN 0
        END
        RETURN 1      
    END
GO

ALTER TABLE VersionTest WITH CHECK ADD  CONSTRAINT [CK_VersionTest] CHECK  (([dbo].[fn_ValidateVersionTest]([ToolID])=(0)))
GO
ALTER TABLE VersionTest CHECK CONSTRAINT [CK_VersionTest]
GO

以下 INSERT 语句可以正常工作。

INSERT INTO VersionTest (ToolID, VersionID, IsActiveVersion, IsBetaVersion)
VALUES (1, 1, 1, 0)

INSERT INTO VersionTest (ToolID, VersionID, IsActiveVersion, IsBetaVersion)
VALUES (1, 2, 0, 0)

正如预期的那样,这个 INSERT 语句失败了:

INSERT INTO VersionTest (ToolID, VersionID, IsActiveVersion, IsBetaVersion)
VALUES (2, 1, 0, 0)

但是,以下 UPDATE 和 DELETE 语句并没有像我预期的那样失败:

UPDATE VersionTest 
SET IsActiveVersion = 0, IsBetaVersion = 0
WHERE VersionID = 1

DELETE VersionTest WHERE VersionID = 1

还有其他方法我应该这样做吗?我必须使用触发器吗?

【问题讨论】:

标签: triggers sql-server-2012 check-constraints


【解决方案1】:

我们可以通过这种方式强制检查更新。
假设你有一张这样的表

create table UserTest(Id int, IsEnabled bit, [GroupId] int)

现在,我们要检查[GroupId] 仅启用了 1 个用户。

通常约束看起来像

ALTER TABLE [dbo].[UserTest] ADD CONSTRAINT CHK_OnlyOneEnabled  CHECK (dbo.checkOnlyOne(GroupId)=1)

在您更新 GroupId 之前,不会在已更新的记录上触发此约束。
因此,我们必须强制约束通过执行来验证 IsEnabled 列

ALTER TABLE [dbo].[UserTest] ADD CONSTRAINT CHK_OnlyOneEnabled  CHECK (dbo.checkOnlyOne(GroupId, IsEnabled )=1)

函数中是否使用 IsEnabled 值无关紧要。

【讨论】:

  • 看起来像我的场景,即使函数不使用它也必须传递额外的参数
猜你喜欢
  • 2016-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多