【问题标题】:When are check constraints evaluated?何时评估检查约束?
【发布时间】:2017-06-07 19:29:34
【问题描述】:

我有一个记录表

ID
EntityID 
Value
Status

还有一个实体表

ID
Col1
Col2
CurrentRecordID

CurrentRecordID 应该是与Entity 绑定的Record,Status 为 0

我有两个检查约束 表Entity 上的一个检查以确保CurrentRecordID 实际上是当前记录,Record 上的一个检查以确保如果状态为0,则其EntityID 具有@987654331 @ 匹配其 ID。

所以本质上,这两个检查约束做同样的事情,但分别在每个表上

检查约束是在事务的最后运行还是在每次插入/更新表后像触发器一样运行?

如果它们在每次修改后运行,这两个约束是否会相互冲突(也就是说,约束会在下一个表有机会更新其值之前抛出错误)。

这是一个运行以插入新记录并将其设置为给定实体的当前记录的查询示例

UPDATE Record SET Status = 1 WHERE Status = 0 AND EntityID = @EntityID
INSERT INTO Record(EntityID, Value, Status) VALUES(@EntityID, 100, 0)
DECLARE @RecordID INT = @@IDENTITY
UPDATE Entity SET CurrentRecordID = RecordID WHERE ID = @EntityID

【问题讨论】:

  • 约束不像触发器那样运行。他们在对数据进行更改之前评估规则。我还告诫不要使用@@IDENTITY,您应该改用SCOPE_IDENTITY。如果 Record 表上有一个触发器插入到另一个具有标识的表中,您将收到该值,而不是您认为的值。
  • @SeanLange 所以流程是Table 1 Change -> Check Constraint Table 1 -> Table 2 Change -> Check Constraint Table 2 即使他们在同一个事务中,对吗?此外,查询只是一个示例,我实际上为此使用实体框架,但无论如何感谢!
  • 没错。尝试更改数据时会发生约束检查。如果对 Table1 的尝试更改未通过检查约束,它将通过异常。
  • @SeanLange 太好了,谢谢。我最终使用计算列来解决我的问题。如果你想用你的解决方案来回答,我很乐意接受。

标签: sql-server check-constraints


【解决方案1】:

约束不像触发器那样运行。他们在对数据进行更改之前评估规则。

在尝试更改数据时进行约束检查。如果对 Table1 的尝试更改未通过检查约束,它将通过异常。

【讨论】:

  • 请允许我补充一点,删除检查不会被执行,因此数据更改将仅限于插入和更新,而不是删除。
  • @Victor 你能详细说明你的意思吗?为每个 DML 操作评估约束。必须检查外键。
  • 如果您查看下面的示例并在运行脚本后执行,例如以下语句 delete from pepe where id = 1,您将看到未执行 CHECK(因为未开始记录 RAISE INFO 'Displaying existing pepe records'; )
  • 好吧,你的例子是在 postgres 中,但问题是关于 sql server。并且完全不确定删除评论与此有什么关系。如果约束是关于当前表的合法值,它当然不会在删除时检查它。为什么会呢?这样做是没有意义的。
  • 好吧,肖恩,我不是说你错了......我只是指出在 postgres 上检查约束不会在任何类型的 data change is attempted 上执行(那些是您的话)和删除可能被视为数据的更改。你是对的,这个问题是关于 sql server 的。我想知道是否在 sql server 中删除触发器检查约束。正如我们都认为的那样,没有必要这样做。
【解决方案2】:

为了完成 Sean Lange 的解释,请允许我留下一个准备运行的示例,以便您亲眼看看在任何数据修改之前如何执行 table check。

CREATE TABLE pepe (
    id serial,
    state text NOT NULL
);
ALTER TABLE pepe ADD CONSTRAINT pepe_pk PRIMARY KEY (id);


CREATE OR REPLACE FUNCTION pepe_check_func() RETURNS boolean AS
$BODY$
  DECLARE
    temp_row record;
  BEGIN
    RAISE INFO 'Displaying existing pepe records';
    FOR temp_row IN
        SELECT id,state
        FROM pepe
    LOOP
        RAISE INFO '(id,state) = (%,%)',temp_row.id, temp_row.state;
    END LOOP;
    RETURN TRUE;
  END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;

ALTER TABLE pepe ADD CONSTRAINT pepe_check
CHECK (pepe_check_func());


insert into pepe (state) values ('go');

update pepe
set state = 'active';

select *
from pepe;

【讨论】:

  • 这个例子是在 postgres 中的,请随意添加另一个 sql-server 的例子!
猜你喜欢
  • 1970-01-01
  • 2023-01-31
  • 1970-01-01
  • 2011-01-28
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多