我是T-SQL中的新手,我遇到了一些带有事务,游标和存储过程的大型脚本。所以,我的代码是这样的(这个代码只是我的脚本结构的一个例子,实际上我在OuterProc游标内部有多个过程,InnerProc游标内有多个操作):
create proc InnerProc
as
begin
declare @Id int
begin tran
declare mycursor cursor local static read_only forward_only
for select Id
from MyOtherTable
open mycursor
fetch next from mycursor into @Id
while @@fetch_status = 0
begin
select 1/0
if @@ERROR <> 0
begin
rollback tran
return @@ERROR
end
fetch next from mycursor into @Id
end
close mycursor
deallocate mycursor
commit tran
end
create proc OuterProc
as
begin
declare @Id int
begin tran
declare mycursor cursor local static read_only forward_only
for select Id
from MyTable
open mycursor
fetch next from mycursor into @Id
while @@fetch_status = 0
begin
exec @error = InnerProc
if @@ERROR <> 0
begin
rollback tran
return
end
else
commit tran
fetch next from mycursor into @Id
end
close mycursor
deallocate mycursor
end
使用这种结构我有这个错误:
Msg 515, Level 16, State 2, Procedure InnerProc, Line 448
Cannot insert the value NULL into column 'InitialQuantity', table 'MySecondTable'; column does not allow nulls. INSERT fails.
The statement has been terminated.
Msg 266, Level 16, State 2, Procedure InnerProc, Line 0
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 0.
Msg 3903, Level 16, State 1, Procedure CreateSASEExtraction, Line 79
The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION.
我的代码出了什么问题?如果innerProc内部出现问题,我希望该外部游标的所有操作都回滚并停止内部游标。如果在outerProc中出现问题,我希望该游标的所有操作都回滚,但我希望该游标继续循环...
还有更好的方法吗?
更新
在我纠正了@Bernd Linde检测到的一些错误之后,我在InnerProc中添加了一个try-catch,并命名了InnerProc事务。现在我有了这段代码:
create proc InnerProc
as
begin
declare @Id int
begin tran
begin try
declare mycursor cursor local static read_only forward_only
for select Id
from MyOtherTable
open mycursor
fetch next from mycursor into @Id
while @@fetch_status = 0
begin
select 1/0
if @@ERROR <> 0
return @@ERROR
fetch next from mycursor into @Id
end
close mycursor
deallocate mycursor
commit tran
return 0
end try
begin catch
return @@ERROR
end catch
end
create proc OuterProc
as
begin
declare @Id int
declare mycursor cursor local static read_only forward_only
for select Id
from MyTable
open mycursor
fetch next from mycursor into @Id
while @@fetch_status = 0
begin
begin tran
exec @error = InnerProc
if @@ERROR <> 0
begin
rollback tran
return
end
else
commit tran
fetch next from mycursor into @Id
end
close mycursor
deallocate mycursor
end
但现在我还有其他错误消息:
Msg 266, Level 16, State 2, Procedure InnerProc, Line 0
Transaction count after EXECUTE indicates a mismatching number of BEGIN and COMMIT statements. Previous count = 1, current count = 2.
我该如何解决这个问题?
答案 0 :(得分:1)
从第一眼看,你在循环中提交事务,但是你只是在循环之外启动它们
因此,每次循环进入第二次迭代时,它将尝试提交或回滚不存在的事务,因此您将收到错误"The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION."
我建议在MSDN here
上阅读SQLServer中的事务答案 1 :(得分:0)
经过多次尝试后,我终于明白了。
InnerProc必须只有COMMIT,而OuterProc将负责回滚。 为此,当InnerProc导致一些必须在OuterProc中捕获的错误并被强制像异常一样。 我想如何继续在OuterProc中循环,该过程必须有一个try-catch,其中强制循环并且回滚完成。
为了更好的交易号码控制,我使用了@@ TRANCOUNT。
所以我用这段代码解决了这个问题:
create proc InnerProc
as
begin
declare @Id int
begin try
begin tran
declare mycursor cursor local static read_only forward_only
for select Id
from MyOtherTable
open mycursor
fetch next from mycursor into @Id
while @@fetch_status = 0
begin
select 1/0
IF @@ERROR <> 0
begin
if @@TRANCOUNT > 0
rollback tran
close mycursor
deallocate mycursor
return @@ERROR
end
fetch next from mycursor into @Id
end
close mycursor
deallocate mycursor
commit tran
return 0
end try
begin catch
close mycursor
deallocate mycursor
return @@ERROR
end catch
end
create proc OuterProc
as
begin
declare @Id int
declare mycursor cursor local static read_only forward_only
for select Id
from MyTable
open mycursor
fetch next from mycursor into @Id
while @@fetch_status = 0
begin
begin tran
begin try
exec @error = InnerProc
if @@ERROR <> 0
RAISERROR('Exception',1,1)
if@@TRANCOUNT > 0
commit tran
fetch next from mycursor into @Id, @Name, @CodeDGAE, @Code, @NUIT, @Project
end try
begin catch
if @@TRANCOUNT > 0
rollback tran
fetch next from mycursor into @Id, @Name, @CodeDGAE, @Code, @NUIT, @Project
end catch
end
close mycursor
deallocate mycursor
end