Я довольно новичок в 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, я хочу, чтобы все операции для этого курсора были отменены, но я хочу, чтобы этот курсор продолжал цикл ...
Есть лучший способ сделать это?
UPDATE:
После того как я исправить некоторые ошибки @Bernd Linde обнаружены, добавить примерочный улов в InnerProc и я назвал сделку 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.
Как я могу решить эту проблему?
почему вы используете курсор на всех? – HLGEM
@HLGEM, потому что мне нужно выполнить некоторые операции для каждой строки определенной таблицы. – Ninita
Это не требует указателя. Курсоры - убийца производительности и должны быть в крайнем случае. Никто, кроме администратора баз данных с опытом работы не менее 10 лет, даже не должен использовать их вообще. – HLGEM