Ich habe eine gespeicherte Prozedur, die in einem Insert-Exec-Block aufgerufen wird:
insert into @t
exec('test')
Wie kann ich mit Ausnahmen umgehen, die in der gespeicherten Prozedur generiert wurden, und trotzdem die Verarbeitung fortsetzen?
Der folgende Code veranschaulicht das Problem. Ich möchte je nach Erfolg oder Misserfolg des internen exec()
Anrufs 0 oder -1 zurückgeben :
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;
Mein Problem ist das return(-1)
. Der Erfolgspfad ist in Ordnung.
Wenn ich den try / catch-Block in der gespeicherten Prozedur weglasse, wird der Fehler ausgelöst und das Einfügen schlägt fehl. Ich möchte jedoch den Fehler behandeln und einen schönen Wert zurückgeben.
Der Code wie er ist gibt die Nachricht zurück:
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.
Dies ist vielleicht die schlimmste Fehlermeldung, die mir begegnet ist. Es scheint wirklich zu bedeuten, dass Sie in einer verschachtelten Transaktion keinen Fehler behandelt haben.
Wenn ich das eingebe if @@TRANCOUNT > 0
, bekomme ich die Nachricht:
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.
Ich habe versucht, mit begin / commit-Transaktionsanweisungen herumzuspielen, aber nichts scheint zu funktionieren.
Wie kann meine gespeicherte Prozedur Fehler behandeln, ohne die gesamte Transaktion abzubrechen?
Bearbeiten als Antwort auf Martin:
Der eigentliche Aufrufcode lautet:
declare @RetvalTable table (retval int);
set @retval = -1;
insert into @RetvalTable
exec('
deklariere @retval int; exec @retval = '+ @ query +'; wähle @retval ');
select @retval = retval from @RetvalTable;
Wo @query
ist der Aufruf der gespeicherten Prozedur? Ziel ist es, den Rückgabewert aus der gespeicherten Prozedur zu erhalten. Wenn dies ohne insert
(oder genauer gesagt ohne Starten einer Transaktion) möglich ist, wäre das großartig.
Ich kann die gespeicherten Prozeduren im Allgemeinen nicht ändern, um den Wert in einer Tabelle zu speichern, da zu viele davon vorhanden sind. Einer von ihnen schlägt fehl, und das kann ich ändern. Meine derzeit beste Lösung ist ungefähr:
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
am Ende. Wenn Sie einen anderen Weg kennen, um den Rückgabewert von einem dynamischen Aufruf einer gespeicherten Prozedur zu erhalten, würde ich gerne wissen.
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;
funktioniert gut.