ฉันมีขั้นตอนการจัดเก็บที่เรียกว่าในบล็อคแทรก-exec:
insert into @t
exec('test')
ฉันจะจัดการกับข้อยกเว้นที่สร้างขึ้นในขั้นตอนการจัดเก็บและยังคงดำเนินการต่อได้อย่างไร
รหัสต่อไปนี้แสดงให้เห็นถึงปัญหา สิ่งที่ฉันต้องการจะทำคือคืน 0 หรือ -1 ขึ้นอยู่กับความสำเร็จหรือความล้มเหลวของการexec()โทรภายใน:
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;
return(-1)ปัญหาของฉันคือ เส้นทางสู่ความสำเร็จนั้นดี
ถ้าฉันปล่อยบล็อก try / catch ออกจากโพรซีเดอร์ที่เก็บไว้แสดงว่าเกิดข้อผิดพลาดและการแทรกล้มเหลว อย่างไรก็ตามสิ่งที่ฉันต้องการทำคือจัดการข้อผิดพลาดและคืนค่าที่ดี
โค้ดตามที่ส่งคืนข้อความ:
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.
นี่อาจเป็นข้อความแสดงข้อผิดพลาดที่แย่ที่สุดที่ฉันเคยพบ ดูเหมือนว่าหมายถึง "คุณไม่ได้จัดการกับข้อผิดพลาดในการทำธุรกรรมที่ซ้อนกัน"
ถ้าฉันใส่เข้าไปif @@TRANCOUNT > 0ฉันก็จะได้รับข้อความ:
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.
ฉันได้ลองเล่นโดยเริ่มต้น / คอมมิชชันธุรกรรม แต่ดูเหมือนว่าไม่มีอะไรทำงาน
ดังนั้นฉันจะให้ขั้นตอนการจัดเก็บของฉันจัดการข้อผิดพลาดโดยไม่ยกเลิกการทำธุรกรรมโดยรวมได้อย่างไร
แก้ไขเพื่อตอบสนองต่อ Martin:
รหัสการโทรจริงคือ:
declare @RetvalTable table (retval int);
set @retval = -1;
insert into @RetvalTable
exec('
ประกาศ @ ย้อนกลับ int; exec @retval = '+ @ query +'; เลือก @retval ');
select @retval = retval from @RetvalTable;
@queryการเรียกขั้นตอนการจัดเก็บอยู่ที่ไหน เป้าหมายคือการรับค่าตอบแทนจากขั้นตอนการจัดเก็บ หากเป็นไปได้โดยไม่ต้องinsert(หรือเฉพาะเจาะจงมากขึ้นโดยไม่ต้องเริ่มทำธุรกรรม) นั่นจะเป็นสิ่งที่ดี
ฉันไม่สามารถแก้ไขขั้นตอนการจัดเก็บโดยทั่วไปเพื่อเก็บค่าในตารางได้เนื่องจากมีจำนวนมากเกินไป หนึ่งในนั้นคือความล้มเหลวและฉันสามารถแก้ไขได้ ทางออกที่ดีที่สุดในปัจจุบันของฉันคือ:
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ในตอนท้าย หากคุณรู้วิธีอื่นในการรับค่าตอบแทนจากการเรียกขั้นตอนการจัดเก็บแบบไดนามิกฉันชอบที่จะรู้
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;ทำงานได้ดี