Saya memiliki prosedur tersimpan yang disebut dalam blok insert-exec:
insert into @t
exec('test')
Bagaimana saya bisa menangani pengecualian yang dihasilkan dalam prosedur tersimpan dan masih melanjutkan pemrosesan?
Kode berikut menggambarkan masalah. Yang ingin saya lakukan adalah mengembalikan 0 atau -1 tergantung pada keberhasilan atau kegagalan exec()
panggilan internal :
alter procedure test -- or create
as
begin try
declare @retval int;
-- This code assumes that PrintMax exists already so this generates an error
exec('create procedure PrintMax as begin print ''hello world'' end;')
set @retval = 0;
select @retval;
return(@retval);
end try
begin catch
-- if @@TRANCOUNT > 0 commit;
print ERROR_MESSAGE();
set @retval = -1;
select @retval;
return(@retval);
end catch;
go
declare @t table (i int);
insert into @t
exec('test');
select *
from @t;
Masalah saya adalah return(-1)
. Jalur sukses baik-baik saja.
Jika saya meninggalkan blok coba / tangkap dalam prosedur tersimpan, maka kesalahan dinaikkan dan insert gagal. Namun, yang ingin saya lakukan adalah menangani kesalahan dan mengembalikan nilai yang bagus.
Kode as is mengembalikan pesan:
Msg 3930, Level 16, State 1, Line 6
The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction.
Ini mungkin pesan kesalahan terburuk yang saya temui. Tampaknya benar-benar berarti "Anda tidak menangani kesalahan dalam transaksi bersarang."
Jika saya memasukkan if @@TRANCOUNT > 0
, maka saya mendapatkan pesan:
Msg 3916, Level 16, State 0, Procedure gordontest, Line 7
Cannot use the COMMIT statement within an INSERT-EXEC statement unless BEGIN TRANSACTION is used first.
Saya sudah mencoba bermain-main dengan memulai / melakukan pernyataan transaksi, tetapi sepertinya tidak ada yang berhasil.
Jadi, bagaimana saya bisa memiliki prosedur tersimpan menangani kesalahan tanpa membatalkan transaksi keseluruhan?
Edit dalam menanggapi Martin:
Kode panggilan sebenarnya adalah:
declare @RetvalTable table (retval int);
set @retval = -1;
insert into @RetvalTable
exec('
mendeklarasikan @retval int; exec @retval = '+ @ query +'; pilih @retval ');
select @retval = retval from @RetvalTable;
Di mana @query
prosedur panggilan tersimpan? Tujuannya adalah untuk mendapatkan nilai balik dari prosedur tersimpan. Jika ini dimungkinkan tanpa insert
(atau, lebih khusus, tanpa memulai transaksi), itu akan bagus.
Saya tidak bisa mengubah prosedur yang tersimpan secara umum untuk menyimpan nilai dalam tabel, karena ada terlalu banyak. Salah satunya gagal, dan saya bisa memodifikasinya. Solusi terbaik saya saat ini adalah sesuatu seperti:
if (@StoredProcedure = 'sp_rep__post') -- causing me a problem
begin
exec @retval = sp_rep__post;
end;
else
begin
-- the code I'm using now
end;
sumber
declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;
bekerja dengan baik.select @retval; return @retval
di bagian akhir. Jika Anda tahu cara lain untuk mendapatkan nilai kembali dari panggilan prosedur tersimpan dinamis, saya ingin tahu.DECLARE @RC INT;EXEC sp_executesql N'EXEC @RC = test', N'@RC INT OUTPUT', @RC = @RC OUTPUT;insert into @t VALUES (@RC)
Jawaban:
Kesalahan pada
EXEC
bagian dariINSERT-EXEC
pernyataan itu membuat transaksi Anda dalam keadaan hancur.Jika Anda
PRINT
keluarXACT_STATE()
diCATCH
blok itu diatur ke-1
.Tidak semua kesalahan akan mengatur keadaan ini. Galat kendala periksa berikut melewati ke blok tangkap dan
INSERT
berhasil.Menambahkan ini ke
CATCH
blokTidak membantu Ini memberi kesalahan
Saya tidak berpikir ada cara untuk pulih dari kesalahan seperti itu setelah itu terjadi. Namun untuk kasus penggunaan spesifik Anda, Anda tidak perlu
INSERT ... EXEC
melakukannya. Anda dapat menetapkan nilai kembali ke variabel skalar lalu menyisipkannya dalam pernyataan terpisah.Atau tentu saja Anda dapat merestrukturisasi prosedur tersimpan yang disebut sehingga tidak menimbulkan kesalahan sama sekali.
sumber