函数在 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

似乎在初始插入之后才执行检查约束。所以数据库引擎

  1. 插入数据
  2. 检查约束
  3. 如果插入违反约束,回滚插入
  4. 如果插入没问题,提交数据

您可以看到这在查询执行计划中发生的顺序:

图片中突出显示的断言的属性描述为“用于验证指定条件是否存在”。

我无法从 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);