【发布时间】:2013-08-23 15:46:31
【问题描述】:
我正在尝试对表执行数据验证,我需要检查多个行和列。基本上,我想确保对于任何给定的工具,至少存在一个标记为 Active 版本或 Beta 版本的版本。
我认为检查这一点的唯一方法是通过用户定义的标量函数和调用该函数的CHECK 约束。我能够创建返回我期望的函数(如果正常,则为 0,如果不正常,则为 1)并且它可以工作......但 仅 在INSERT 上。当我执行UPDATE 或DELETE 语句时,检查约束不会失败,因此在任何一种情况下我都会得到错误的数据。
这是我正在使用的表格和函数的示例。
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
还有其他方法我应该这样做吗?我必须使用触发器吗?
【问题讨论】:
-
请停止组合检查约束和 UDF。 Several articles here explain how wrong this can go.
标签: triggers sql-server-2012 check-constraints