it-swarm.com.de

wie man die gleiche Ausnahme in SQL Server erneut auslöst

Ich möchte dieselbe Ausnahme in SQL Server erneut auslösen, die in meinem try-Block aufgetreten ist. Ich kann dieselbe Nachricht ausgeben, möchte aber denselben Fehler ausgeben.

BEGIN TRANSACTION
    BEGIN TRY
            INSERT INTO Tags.tblDomain 
            (DomainName, SubDomainId, DomainCode, Description)
            VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
            COMMIT TRANSACTION
    END TRY

    BEGIN CATCH
            declare @severity int; 
            declare @state int;

            select @severity=error_severity(), @state=error_state();

            RAISERROR(@@Error,@ErrorSeverity,@state);
            ROLLBACK TRANSACTION
    END CATCH

RAISERROR(@@Error, @ErrorSeverity, @state);

Diese Zeile wird einen Fehler anzeigen, aber ich möchte eine solche Funktionalität. Dies löst einen Fehler mit der Fehlernummer 50000 aus, aber ich möchte, dass die Fehlernummer geworfen wird, die ich übergebe @@error,

Ich möchte diesen Fehler nicht am Frontend erfassen

d.h.

catch (SqlException ex)
{
if ex.number==2627
MessageBox.show("Duplicate value cannot be inserted");
}

Ich möchte diese Funktionalität. was mit raiseerror nicht erreicht werden kann. Ich möchte keine benutzerdefinierte Fehlermeldung am Back-End geben.

RAISEERROR sollte unterhalb des genannten Fehlers zurückkehren, wenn ich ErrorNo übergebe, um in catch geworfen zu werden

Msg 2627, Level 14, State 1, Procedure spOTest_DomainInsert,

Zeile 14 Verletzung der UNIQUE KEY-Einschränkung 'UK_DomainCode'. Doppelter Schlüssel kann nicht in Objekt 'Tags.tblDomain' eingefügt werden. Die Anweisung wurde beendet.

BEARBEITEN:

Was kann der Nachteil sein, wenn kein try catch-Block verwendet wird, wenn eine Ausnahme am Frontend behandelt werden soll, wenn die gespeicherte Prozedur mehrere Abfragen enthält, die ausgeführt werden müssen

68
Shantanu Gupta

Im Folgenden finden Sie ein voll funktionsfähiges, sauberes Codebeispiel, mit dem eine Reihe von Anweisungen zurückgesetzt werden können, wenn ein Fehler auftritt, und die Fehlermeldung melden.

begin try
    begin transaction;

    ...

    commit transaction;
end try
begin catch
    declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
    select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
    rollback transaction;
    raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
96
Ben Gripka

SQL 2012 führt die throw-Anweisung ein:

http://msdn.Microsoft.com/de-de/library/ee677615.aspx

Wenn die THROW-Anweisung ohne Parameter angegeben wird, muss sie angezeigt werden in einem CATCH-Block. Dadurch wird die erfasste Ausnahme ausgelöst.

BEGIN TRY
    BEGIN TRANSACTION
    ...
    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION;
    THROW
END CATCH
105
Michael

Erneutes Einsetzen des CATCH-Blocks (vor SQL 2012-Code, verwenden Sie die THROW-Anweisung für SQL 2012 und höher):

DECLARE
    @ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
    @ErrorNumber int = ERROR_NUMBER(),
    @ErrorSeverity int = ERROR_SEVERITY(),
    @ErrorState int = ERROR_STATE(),
    @ErrorLine int = ERROR_LINE(),
    @ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
5
nzeemin

Ich denke, deine Auswahl ist:

  • Fangen Sie den Fehler nicht (lassen Sie ihn aufblähen)
  • Erzeuge eine benutzerdefinierte

Irgendwann wird SQL wahrscheinlich einen Reraise-Befehl einführen oder nur bestimmte Fehler abfangen. Verwenden Sie im Moment eine Problemumgehung. Es tut uns leid.

4
Rob Farley

Das geht nicht: Nur die Engine kann Fehler unter 50000 auslösen. Alles, was Sie tun können, ist eine Ausnahme, die look so aussieht ...

Sehen Sie meine Antwort bitte hier

Der Fragesteller nutzte Transaktionen auf Kundenseite, um das zu tun, was er wollte, was ich für ein bisschen dumm halte ...

1
gbn

Da Sie noch nicht nach 2012 gewechselt sind, können Sie das Sprudeln des ursprünglichen Fehlercodes implementieren, indem Sie den Textnachrichtenteil der Ausnahme verwenden, die Sie aus dem catch-Block werfen (erneut). Denken Sie daran, dass es eine Struktur enthalten kann, z. B. XML-Text, den Ihr Anrufercode in seinem catch-Block analysiert.

0
Yuri Makassiouk

Um die Ausführung in einer gespeicherten Prozedur zu stoppen, nachdem ein Fehler aufgetreten ist, und um den Fehler an das aufrufende Programm zurückzublasen, müssen Sie jeder Anweisung folgen, die mit diesem Code einen Fehler auslösen kann:

If @@ERROR > 0
Return

Ich war selbst überrascht, als ich herausfand, dass die Ausführung in einer gespeicherten Prozedur nach einem Fehler fortgesetzt werden kann. Wenn Sie nicht wissen, dass dies zu Problemen führen kann, kann dies zu Problemen führen.

Diese Art der Fehlerbehandlung entspricht (vor .Net) Visual Basic 6. Wir freuen uns auf den Befehl Throw in SQL Server 2012.

0
Chuck Bevitt

Ok, das ist ein Workaround ... :-)

DECLARE @Error_Number INT
BEGIN TRANSACTION 
    BEGIN TRY
    INSERT INTO Test(Id, Name) VALUES (newID(),'Ashish') 
    /* Column 'Name' has unique constraint on it*/
    END TRY
    BEGIN CATCH

            SELECT ERROR_NUMBER()
            --RAISERROR (@ErrorMessage,@Severity,@State)
            ROLLBACK TRAN
    END CATCH

Wenn Sie den catch-Block beachten, wird der Fehler nicht ausgelöst, sondern die tatsächliche Fehlernummer zurückgegeben (und würde auch die Transaktion rückgängig machen). Wenn Sie jetzt in Ihrem .NET-Code die -Ausnahme abfangen, erhalten Sie, wenn Sie ExecuteScalar () verwenden, die tatsächlich gewünschte Fehlernummer und die entsprechende Nummer.

int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
    MessageBox.Show("Some message");
}

Hoffe das hilft,

BEARBEITEN: - Nur ein Hinweis: Wenn Sie die Anzahl der betroffenen Datensätze abrufen möchten und versuchen, ExecuteNonQuery zu verwenden, funktioniert die obige Lösung möglicherweise nicht für Sie. Ansonsten denke ich, dass es zu dem passt, was Sie brauchen. Gib mir Bescheid.

0
Ashish Gupta

Sie können auch eine gespeicherte Wrapper-Prozedur für diese Szenarien erstellen, wenn die SQL-Anweisung innerhalb der Transaktion ausgeführt werden soll und der Fehler in Ihren Code eingespeist werden soll.

CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
    @SQL nvarchar(max)
)
AS

SET NOCOUNT ON

BEGIN TRY
    BEGIN TRANSACTION
        EXEC(@SQL)
    COMMIT TRANSACTION
END TRY

BEGIN CATCH
    DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
    SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
    ROLLBACK TRANSACTION
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH

GO

-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'
0
Sergey