SQL:是否可以在交易完成之前阻止 table 插入?
SQL: Is it possible to block a table insert just prior to the completion of a transaction?
TL;DR: 我真正的问题在标题中,是否可以在交易完成之前阻止 table 插入,即,仅涉及提交事务之前的数据?
UPDATE: 过程只是一个人为的例子,可能不是一个很好的例子,证明我无法想出一种在包含两个语句的事务完成之前阻止 insertion/update 的方法。我只是想知道有没有办法做到这一点,这个例子有点无关紧要。
(可能不好的)示例:
如果两个 table 中的某些 属性 被破坏,我试图阻止交易发生,举一个简单的例子,假设我想阻止第一个 [=47] 中的一个=]的值(比如ID)已经存在于table 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
因为在交易结束时,第一个 table 的 ID 与 table 中的值相同 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
如何更新我的代码以成功阻止交易?我是否需要将交易重新定义为同一时间?
尝试将触发器更改为在事件之前触发,如:
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
注意:
检查约束只能检查 table 本身。
您还应该学习外键,因为这正是解决您 运行 问题的方法。
不,在 MSSQLSever 中不可能做你想做的事,但它可能在 PostGres 或 Oracle 中。
原因第 1 部分: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 中不可能为 table 插入多个 table 的单一约束,这将在任意事务完成之前阻塞。
还值得一提的是,您想要的称为可延迟约束。 See more about that here.
TL;DR: 我真正的问题在标题中,是否可以在交易完成之前阻止 table 插入,即,仅涉及提交事务之前的数据?
UPDATE: 过程只是一个人为的例子,可能不是一个很好的例子,证明我无法想出一种在包含两个语句的事务完成之前阻止 insertion/update 的方法。我只是想知道有没有办法做到这一点,这个例子有点无关紧要。
(可能不好的)示例:
如果两个 table 中的某些 属性 被破坏,我试图阻止交易发生,举一个简单的例子,假设我想阻止第一个 [=47] 中的一个=]的值(比如ID)已经存在于table 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
因为在交易结束时,第一个 table 的 ID 与 table 中的值相同 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
如何更新我的代码以成功阻止交易?我是否需要将交易重新定义为同一时间?
尝试将触发器更改为在事件之前触发,如:
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
注意:
检查约束只能检查 table 本身。
您还应该学习外键,因为这正是解决您 运行 问题的方法。
不,在 MSSQLSever 中不可能做你想做的事,但它可能在 PostGres 或 Oracle 中。
原因第 1 部分: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 中不可能为 table 插入多个 table 的单一约束,这将在任意事务完成之前阻塞。
还值得一提的是,您想要的称为可延迟约束。 See more about that here.