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;
quelle
declare @t table (i int);declare @RC int;exec @RC = test;insert into @t values (@RC);select * from @t;
funktioniert gut.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)
Antworten:
Der Fehler in dem
EXEC
Teil derINSERT-EXEC
Anweisung führt dazu, dass Ihre Transaktion in einem zum Scheitern verurteilten Zustand bleibt.Wenn Sie
PRINT
herausXACT_STATE()
in demCATCH
Block wird eingestellt-1
.Nicht alle Fehler setzen den Status auf diesen Wert. Der folgende Überprüfungsbeschränkungsfehler geht bis zum catch-Block und der ist
INSERT
erfolgreich.Hinzufügen zum
CATCH
BlockHilft nicht. Es gibt den Fehler
Ich glaube nicht, dass es eine Möglichkeit gibt, einen solchen Fehler zu beheben, wenn er einmal aufgetreten ist. Für Ihren speziellen Anwendungsfall benötigen Sie dies jedoch
INSERT ... EXEC
ohnehin nicht . Sie können den Rückgabewert einer skalaren Variablen zuweisen und diesen dann in eine separate Anweisung einfügen.Oder Sie können die aufgerufene gespeicherte Prozedur natürlich so umstrukturieren, dass dieser Fehler überhaupt nicht auftritt.
quelle