【问题标题】:SQL: Is it possible to block a table insert just prior to the completion of a transaction?SQL:是否可以在事务完成之前阻止表插入?
【发布时间】:2016-02-05 18:04:43
【问题描述】:

TL;DR:我真正的问题是在标题中,是否可以在事务完成之前阻止表插入,也就是说,只涉及数据就在交易提交之前?

更新:所进行的只是一个人为的示例,可能不是一个好的示例,表明我无法想出阻止插入/更新的方法在包含两个语句的事务完成之前。我只是想知道有没有办法做到这一点,这个例子有点无关紧要。

(可能很糟糕)示例:

如果两个表的某些属性被破坏,我试图阻止事务发生,举个简单的例子,假设如果第一个表的值之一(比如 ID)已经存在于表 2 中,我想阻止。

create table dbo.tbl1
(
    id int,
    name varchar(20)
)

create table dbo.tbl2
(
    id int,
    name varchar(20)
)
go

我想失败的事情如下:

begin transaction
    insert into tbl1 values(1, 'tbl1_1')
    insert into tbl2 values(1, 'tbl2_1')
commit transaction

由于在事务结束时第一个表的 id 值与表 2 中的值相同。

但不幸的是,我尝试定义一个触发器来阻止它和一个检查约束,但似乎都没有阻止它。

触发器(as suggested here):

CREATE TRIGGER MyTrigger ON dbo.tbl1
AFTER INSERT, UPDATE
AS

if exists ( select * from tbl2 inner join inserted i on i.id = tbl2.id)
begin
    rollback
    RAISERROR ('Duplicate Data', 16, 1);
end

检查约束(as suggested here):

create function dbo.tbl2WithID(@ID int) returns int
as
begin
    declare @ret int
    select @ret = count(*) from tbl2 where id = @ID
    return @ret
end
go

alter table dbo.tbl1 
add constraint chk_notbl2withid 
check (dbo.tbl2WithID(id) = 0)
go

如何更新我的代码以成功阻止交易?是否需要重新定义交易为同一时间?

【问题讨论】:

  • 如果要向两个表中插入相同的值,为什么不检查传入的值并且根本不插入?
  • 这是什么数据库?你的标签到处都是。您是否有任何理由无法在 tbl1 上定义唯一约束?
  • @shree.pat18:我的目标是让人们定义涉及这两个表的任何事务语句,但要知道他们不能破坏我强加的条件。就像我们定义约束一样,我们不必在每次更新表时都记住该逻辑。
  • @mustaccio: ms-sql-server-2005
  • 首先您将数据插入tb1,然后是tb2,因为您已经在tb1 上定义了触发器。当数据插入tb1时,tb2中不会有匹配记录

标签: sql-server triggers sql-function check-constraints sqltransaction


【解决方案1】:

尝试将触发器更改为在事件之前触发,如下所示:

CREATE TRIGGER MyTrigger ON dbo.tbl1
BEFORE INSERT, UPDATE -- this is changed to "BEFORE"
AS

if exists ( select * from tbl2 inner join inserted i on i.id = tbl2.id)
begin
    rollback
    RAISERROR ('Duplicate Data', 16, 1);
end

注意:

检查约束只能检查表本身。

您还应该学习 FOREIGN KEYS,因为这正是解决您遇到的问题的方法。

【讨论】:

  • 1) 在 t-sql 中没有前置触发器。有 for 和 after(它们是相同的)和代替。 2)检查约束只能在表本身内检查是不正确的,因为显然我的检查约束在其表外检查。 3) 外键用于当你想确保另一个表中存在其他东西时,而不是确保某些东西不存在存在。
【解决方案2】:

不,在 MSSQLSever 中不可能做你想做的事,但它可能在 PostGres 或 Oracle 中。

原因一:It's not possible to insert to two different tables in the same statement.

原因第 2 部分:“SQL Server [does not] allow constraint violations in a transaction as long as the transaction has not been committed yet.

因此,在 SQLServer 中不可能对多个表的表插入有一个约束,该约束将在任意事务完成之前阻塞。

还值得一提的是,您想要的称为可延迟约束。 See more about that here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 2019-12-31
    • 1970-01-01
    • 2020-03-30
    相关资源
    最近更新 更多