【问题标题】:function do not work in CHECK Constraint on sql server函数在 sql server 上的 CHECK Constraint 中不起作用
【发布时间】:2015-01-13 18:44:47
【问题描述】:

我的数据库有问题,我尝试简化我的数据库.. 经过多次尝试该函数使用'X'表,然后在'X'表上使用该函数。你不能使用函数使用同一张表...

--建表后:

create table Items(
ID int,
Price money
);

--插入一些值

insert into Items Values(1,4);
insert into Items Values(2,5);

--创建上表使用的函数

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

--然后alter 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

【问题讨论】:

    标签: sql sql-server database function


    【解决方案1】:

    您遇到的问题是,当检查约束触发时,新值存在于表中(在隐式事务中),因此当您插入 15 时,max(Price) 15,所以满足约束,INSERT 成功。我有一个彻底的谷歌试图找到记录在哪里,但没有找到任何确定的东西。

    实现您想要的效果的另一种方法是使用 INSTEAD OF 触发器,示例如下。

    不过,提个建议——这种验证让我觉得很容易出错。我会尝试将您的极限值与数据分开 - 可能在另一个表中。

    希望这会有所帮助,

    里斯

    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
    

    【讨论】:

      【解决方案2】:

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

      1. 插入数据
      2. 检查约束
      3. 如果插入违反约束,则回滚插入
      4. 如果插入正常,提交数据

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

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

      我无法从 Microsoft 找到有关这方面的文档,如果有人知道在哪里可以找到它,请告诉我。

      【讨论】:

        【解决方案3】:

        试试这个代码。它对我来说很好用。

        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); 
        

        【讨论】:

        • 有趣,遗憾的是没有任何关于此行为的 MS 文档。我想知道将列值传递给函数是否会影响 SQL Server 如何感知它的确定性。我仍然会避免这种方法并找到实现所需结果的替代方法。
        • 有趣,我遇到了同样的问题,我通过将它作为参数传递来修复它,即使我没有在函数内部使用它。
        猜你喜欢
        • 1970-01-01
        • 2010-10-06
        • 2020-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-03
        相关资源
        最近更新 更多