函数在 sql 服务器上的 CHECK 约束中不起作用
function do not work in CHECK Constraint on sql server
我的数据库有问题,我尝试简化我的数据库..
经过多次尝试函数使用 'X' table ,然后在 'X' table.you 上使用函数不能使用函数使用相同的 table...
--创建后table:
create table Items(
ID int,
Price money
);
--插入一些值
insert into Items Values(1,4);
insert into Items Values(2,5);
--创建函数使用上面table
CREATE FUNCTION GetMaxPrice
(
-- Add the parameters for the function here
)
RETURNS Money
AS
BEGIN
-- Declare the return variable here
DECLARE @result money = 5;
select @result = max(Price)
from Items;
-- Return the result of the function
RETURN @result;
END
--然后改变table来添加约束
--接受任何低于或等于 table
的价格
alter table Items add check(Price <= dbo.GetMaxPrice())
--之后,我尝试插入项目
insert into Items Values(3,4);
insert into Items Values(4,15); -- <-- here, I have problem. it inserted in Database..
--why inserted when max value is 5 ??
我使用sql server 2012 Express, Win7
似乎在初始插入之后才执行检查约束。所以数据库引擎
- 插入数据
- 检查约束
- 如果插入违反约束,回滚插入
- 如果插入没问题,提交数据
您可以看到这在查询执行计划中发生的顺序:
图片中突出显示的断言的属性描述为“用于验证指定条件是否存在”。
我无法从 Microsoft 找到关于此的文档,如果有人知道在哪里可以找到它,请告诉我。
你遇到的问题是,当检查约束触发时,新值存在于 table(隐式事务内),所以当你插入 15 时,max(Price) is15,所以满足约束条件,INSERT成功。我进行了全面的 Google 尝试并找到记录此内容的位置,但没有找到任何确定的内容。
另一种实现您所追求的效果的方法是使用 INSTEAD OF 触发器,如下例所示。
不过有一点建议 - 这种验证让我觉得很容易出错。我会尝试将您的极限值与数据分开 - 可能在另一个 table.
希望这对您有所帮助,
里斯
create table dbo.Items(
ID int,
Price money
);
insert into dbo.Items Values(1,4);
insert into dbo.Items Values(2,5);
go
create trigger trgItemsInsert on dbo.Items instead of insert as
begin
-- Lookup current max price
declare @MaxPrice money = (select max(Price) from dbo.Items)
if exists (select 1 from inserted where Price > @MaxPrice)
begin
-- If there is a price greater than the current max then reject the insert
declare @msg varchar(255) = 'Maximum allowed price is ' + cast(@MaxPrice as varchar(32)) + '.'
rollback
raiserror('%s', 16, 1, @msg)
end
else
begin
-- Otherwise perform the insert
insert into dbo.Items
select ID,Price from inserted
end
end
go
insert into dbo.Items Values(3,4);
insert into dbo.Items Values(4,15);
go
select * from dbo.Items
go
尝试使用此代码。它对我来说很好用。
CREATE TABLE item
(
ID INT,
Price MONEY
);
--Insert some values
INSERT INTO item
VALUES (1,
4);
INSERT INTO item
VALUES (2,
5);
--create a function use above table
CREATE FUNCTION GetMax (@price MONEY)
RETURNS MONEY
AS
BEGIN
-- Declare the return variable here
DECLARE @result MONEY = 5;
SELECT @result = max(Price)
FROM item;
IF @price < @result
RETURN 1
RETURN 0
-- Return the result of the function
END
--then alter table to add constraint --accept any price less or equal price on table
ALTER TABLE item
WITH NOCHECK ADD CONSTRAINT ck1 CHECK(dbo.GetMax(Price)=(1))
--ALTER TABLE item
-- DROP CONSTRAINT ck1
--after that, i try to insert item
INSERT INTO item
VALUES (3,
4);
INSERT INTO item
VALUES (4,
15);
我的数据库有问题,我尝试简化我的数据库.. 经过多次尝试函数使用 'X' table ,然后在 'X' table.you 上使用函数不能使用函数使用相同的 table...
--创建后table:
create table Items(
ID int,
Price money
);
--插入一些值
insert into Items Values(1,4);
insert into Items Values(2,5);
--创建函数使用上面table
CREATE FUNCTION GetMaxPrice
(
-- Add the parameters for the function here
)
RETURNS Money
AS
BEGIN
-- Declare the return variable here
DECLARE @result money = 5;
select @result = max(Price)
from Items;
-- Return the result of the function
RETURN @result;
END
--然后改变table来添加约束 --接受任何低于或等于 table
的价格alter table Items add check(Price <= dbo.GetMaxPrice())
--之后,我尝试插入项目
insert into Items Values(3,4);
insert into Items Values(4,15); -- <-- here, I have problem. it inserted in Database..
--why inserted when max value is 5 ??
我使用sql server 2012 Express, Win7
似乎在初始插入之后才执行检查约束。所以数据库引擎
- 插入数据
- 检查约束
- 如果插入违反约束,回滚插入
- 如果插入没问题,提交数据
您可以看到这在查询执行计划中发生的顺序:
图片中突出显示的断言的属性描述为“用于验证指定条件是否存在”。
我无法从 Microsoft 找到关于此的文档,如果有人知道在哪里可以找到它,请告诉我。
你遇到的问题是,当检查约束触发时,新值存在于 table(隐式事务内),所以当你插入 15 时,max(Price) is15,所以满足约束条件,INSERT成功。我进行了全面的 Google 尝试并找到记录此内容的位置,但没有找到任何确定的内容。
另一种实现您所追求的效果的方法是使用 INSTEAD OF 触发器,如下例所示。
不过有一点建议 - 这种验证让我觉得很容易出错。我会尝试将您的极限值与数据分开 - 可能在另一个 table.
希望这对您有所帮助,
里斯
create table dbo.Items(
ID int,
Price money
);
insert into dbo.Items Values(1,4);
insert into dbo.Items Values(2,5);
go
create trigger trgItemsInsert on dbo.Items instead of insert as
begin
-- Lookup current max price
declare @MaxPrice money = (select max(Price) from dbo.Items)
if exists (select 1 from inserted where Price > @MaxPrice)
begin
-- If there is a price greater than the current max then reject the insert
declare @msg varchar(255) = 'Maximum allowed price is ' + cast(@MaxPrice as varchar(32)) + '.'
rollback
raiserror('%s', 16, 1, @msg)
end
else
begin
-- Otherwise perform the insert
insert into dbo.Items
select ID,Price from inserted
end
end
go
insert into dbo.Items Values(3,4);
insert into dbo.Items Values(4,15);
go
select * from dbo.Items
go
尝试使用此代码。它对我来说很好用。
CREATE TABLE item
(
ID INT,
Price MONEY
);
--Insert some values
INSERT INTO item
VALUES (1,
4);
INSERT INTO item
VALUES (2,
5);
--create a function use above table
CREATE FUNCTION GetMax (@price MONEY)
RETURNS MONEY
AS
BEGIN
-- Declare the return variable here
DECLARE @result MONEY = 5;
SELECT @result = max(Price)
FROM item;
IF @price < @result
RETURN 1
RETURN 0
-- Return the result of the function
END
--then alter table to add constraint --accept any price less or equal price on table
ALTER TABLE item
WITH NOCHECK ADD CONSTRAINT ck1 CHECK(dbo.GetMax(Price)=(1))
--ALTER TABLE item
-- DROP CONSTRAINT ck1
--after that, i try to insert item
INSERT INTO item
VALUES (3,
4);
INSERT INTO item
VALUES (4,
15);