尽管函数 returns 正确,但更新时使用函数的检查约束失败
Check constraint with function fails on update although function returns correctly
我正在尝试在 table CheckTable 上实现 CHECK constraint 以确保只有一行具有相同 [=19= 的给定行数]col2 值可以将 ok 位设置为 1。
这是我要解决的问题,我正在努力理解如何在检查约束中使用该函数,因为第二次更新通过了检查,尽管该函数似乎可以正常工作
CREATE TABLE [dbo].[CheckTable] (col1 int, col2 int, ok bit)
GO
CREATE FUNCTION [dbo].[CheckIfOk]
(
@col2 int
)
RETURNS bit
AS
BEGIN
DECLARE @OK bit;
IF(EXISTS(SELECT * FROM [dbo].[CheckTable] WHERE col2 = @col2 AND ok = 1))
SET @OK = 1
ELSE
SET @OK = 0
RETURN @OK
END
GO
ALTER TABLE [dbo].[CheckTable]
ADD CONSTRAINT chk_col2_ok CHECK (dbo.CheckIfOk(col2) = 0)
GO
INSERT INTO [dbo].[CheckTable] (col1, col2, ok) VALUES (1, 1, 0),(2, 1, 0)
GO
SELECT [dbo].[CheckIfOk](1)
GO
UPDATE [dbo].[CheckTable] SET ok = 1 WHERE col1 = 1
GO
SELECT [dbo].[CheckIfOk](1)
GO
UPDATE [dbo].[CheckTable] SET ok = 1 WHERE col1 = 2
GO
这可能很明显,但我似乎无法理解。
只是不要 - 标量函数是臭名昭著的效率问题。您的目标可以更好地(IMO)通过更简单的方法实现 - 一个独特的过滤索引。
if object_id('dbo.CheckTable') is not null
drop table dbo.CheckTable;
go
CREATE TABLE [dbo].[CheckTable] (col1 int, col2 int, ok bit)
GO
create unique nonclustered index ixx on dbo.CheckTable(col2) where ok = 1;
go
-- all valid
insert dbo.CheckTable(col1, col2, ok)
values (1, 1, 0), (2, 2, 1), (3, 0, 0);
go
-- still valid
insert dbo.CheckTable(col1, col2, ok)
values (4, 1, 1);
go
-- not valid
insert dbo.CheckTable(col1, col2, ok)
values (5, 1, 1);
go
-- not valid, dup in inserted batch
insert dbo.CheckTable(col1, col2, ok)
values (6, 8, 1), (7, 8, 1);
go
-- valid
insert dbo.CheckTable(col1, col2, ok)
values (9, 1, 0);
go
select * from dbo.CheckTable order by col2, ok, col1;
go
整体设计有缺陷,应该换成过滤后的UNIQUE索引。
"This is my go at the problem, and I am struggling to understand how to use the function in the check constraint as the second update passes the check although the function seems work correctly"
检查约束不是 "fired"。
-- original
UPDATE [dbo].[CheckTable] SET ok = 1 WHERE col1 = 1;
-- enforcing col2 update: 1:1 -> no real change
UPDATE [dbo].[CheckTable] SET ok = 1, col2=col2 WHERE col1 = 1;
结果:
Msg 547 Level 16 State 0 Line 1
The UPDATE statement conflicted with the CHECK constraint "chk_col2_ok".
相关:MSSQL: Update statement avoiding the CHECK constraint
我正在尝试在 table CheckTable 上实现 CHECK constraint 以确保只有一行具有相同 [=19= 的给定行数]col2 值可以将 ok 位设置为 1。
这是我要解决的问题,我正在努力理解如何在检查约束中使用该函数,因为第二次更新通过了检查,尽管该函数似乎可以正常工作
CREATE TABLE [dbo].[CheckTable] (col1 int, col2 int, ok bit)
GO
CREATE FUNCTION [dbo].[CheckIfOk]
(
@col2 int
)
RETURNS bit
AS
BEGIN
DECLARE @OK bit;
IF(EXISTS(SELECT * FROM [dbo].[CheckTable] WHERE col2 = @col2 AND ok = 1))
SET @OK = 1
ELSE
SET @OK = 0
RETURN @OK
END
GO
ALTER TABLE [dbo].[CheckTable]
ADD CONSTRAINT chk_col2_ok CHECK (dbo.CheckIfOk(col2) = 0)
GO
INSERT INTO [dbo].[CheckTable] (col1, col2, ok) VALUES (1, 1, 0),(2, 1, 0)
GO
SELECT [dbo].[CheckIfOk](1)
GO
UPDATE [dbo].[CheckTable] SET ok = 1 WHERE col1 = 1
GO
SELECT [dbo].[CheckIfOk](1)
GO
UPDATE [dbo].[CheckTable] SET ok = 1 WHERE col1 = 2
GO
这可能很明显,但我似乎无法理解。
只是不要 - 标量函数是臭名昭著的效率问题。您的目标可以更好地(IMO)通过更简单的方法实现 - 一个独特的过滤索引。
if object_id('dbo.CheckTable') is not null
drop table dbo.CheckTable;
go
CREATE TABLE [dbo].[CheckTable] (col1 int, col2 int, ok bit)
GO
create unique nonclustered index ixx on dbo.CheckTable(col2) where ok = 1;
go
-- all valid
insert dbo.CheckTable(col1, col2, ok)
values (1, 1, 0), (2, 2, 1), (3, 0, 0);
go
-- still valid
insert dbo.CheckTable(col1, col2, ok)
values (4, 1, 1);
go
-- not valid
insert dbo.CheckTable(col1, col2, ok)
values (5, 1, 1);
go
-- not valid, dup in inserted batch
insert dbo.CheckTable(col1, col2, ok)
values (6, 8, 1), (7, 8, 1);
go
-- valid
insert dbo.CheckTable(col1, col2, ok)
values (9, 1, 0);
go
select * from dbo.CheckTable order by col2, ok, col1;
go
整体设计有缺陷,应该换成过滤后的UNIQUE索引。
"This is my go at the problem, and I am struggling to understand how to use the function in the check constraint as the second update passes the check although the function seems work correctly"
检查约束不是 "fired"。
-- original
UPDATE [dbo].[CheckTable] SET ok = 1 WHERE col1 = 1;
-- enforcing col2 update: 1:1 -> no real change
UPDATE [dbo].[CheckTable] SET ok = 1, col2=col2 WHERE col1 = 1;
结果:
Msg 547 Level 16 State 0 Line 1
The UPDATE statement conflicted with the CHECK constraint "chk_col2_ok".
相关:MSSQL: Update statement avoiding the CHECK constraint