Tôi có một thủ tục được lưu trữ được gọi trong khối insert-exec:
insert into @t
exec('test')
Làm cách nào tôi có thể xử lý các ngoại lệ được tạo trong quy trình được lưu trữ và vẫn tiếp tục xử lý?
Các mã sau đây minh họa vấn đề. Những gì tôi muốn làm là trả về 0 hoặc -1 tùy thuộc vào thành công hay thất bại của exec()
cuộc gọi nội bộ :
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;
Vấn đề của tôi là return(-1)
. Con đường thành công là tốt.
Nếu tôi bỏ qua khối thử / bắt trong quy trình được lưu trữ, thì lỗi sẽ xuất hiện và quá trình chèn không thành công. Tuy nhiên, điều tôi muốn làm là xử lý lỗi và trả về một giá trị đẹp.
Mã như trả về thông báo:
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.
Đây có lẽ là thông báo lỗi tồi tệ nhất mà tôi gặp phải. Nó dường như thực sự có nghĩa là "Bạn đã không xử lý một lỗi trong giao dịch lồng nhau."
Nếu tôi đặt vào if @@TRANCOUNT > 0
, thì tôi nhận được tin nhắn:
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.
Tôi đã thử chơi xung quanh với các báo cáo giao dịch bắt đầu / cam kết, nhưng dường như không có gì hoạt động.
Vì vậy, làm cách nào để thủ tục lưu trữ của tôi xử lý lỗi mà không hủy bỏ giao dịch tổng thể?
Chỉnh sửa để đáp lại Martin:
Mã gọi thực tế là:
declare @RetvalTable table (retval int);
set @retval = -1;
insert into @RetvalTable
exec('
khai báo @retval int; exec @retval = '+ @ truy vấn +'; chọn @retval ');
select @retval = retval from @RetvalTable;
Ở đâu @query
là cuộc gọi thủ tục lưu trữ. Mục tiêu là để có được giá trị trả về từ thủ tục được lưu trữ. Nếu điều này là có thể mà không có insert
(hoặc cụ thể hơn là không bắt đầu giao dịch), điều đó sẽ rất tuyệt.
Tôi không thể sửa đổi các thủ tục được lưu trữ nói chung để lưu trữ giá trị trong một bảng, vì có quá nhiều trong số chúng. Một trong số đó là thất bại, và tôi có thể sửa đổi điều đó. Giải pháp tốt nhất hiện tại của tôi là một cái gì đó như:
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;
select @retval; return @retval
ở cuối. Nếu bạn biết một cách khác để nhận giá trị trả về từ một cuộc gọi thủ tục được lưu trữ động, tôi rất muốn biết.
DECLARE @RC INT;EXEC sp_executesql N'EXEC @RC = test', N'@RC INT OUTPUT', @RC = @RC OUTPUT;insert into @t VALUES (@RC)
declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;
hoạt động tốt