Za pomocą TRY... CATCH instrukcji języka Transact-SQL

Błędy w Transact-SQL Kod może być przetwarzane przy użyciu konstrukcji TRY…CATCH, podobne do funkcji obsługi wyjątków Microsoft Program Visual C++ i Microsoft Program Visual C# języków. Konstrukcja TRY…CATCH składa się z dwóch części: Blok TRY i bloku CATCH. Gdy zostanie wykryty błąd w Transact-SQL Instrukcja, która znajduje się wewnątrz blok TRY, kontrola jest przekazywana do blok CATCH błędu mogą być przetwarzane.

Po blok CATCH obsługuje dany wyjątek, formant jest następnie przenoszone do pierwszego Transact-SQL Instrukcja, znajdujący się w instrukcji END CATCH. If the END CATCH statement is the last statement in a stored procedure or trigger, control is returned to the code that invoked the stored procedure or trigger.Transact-SQL statements in the TRY block following the statement that generates an error will not be executed.

W przypadku błędów wewnątrz blok TRY formantu przekazuje do instrukcja znajdującej się bezpośrednio po skojarzone instrukcja END CATCH.Jeśli instrukcja END CATCH jest ostatniej instrukcji w procedurze przechowywanej lub wyzwalacza, kontrola jest przekazywana do instrukcji, która wywołała procedura przechowywana lub wyzwalacza.

Blok TRY zaczyna się od instrukcja BEGIN TRY i kończy instrukcją END TRY.Jeden lub więcej Transact-SQL instrukcje można określić między instrukcji BEGIN TRY i END TRY.

Blok TRY musi następować bezpośrednio bloku CATCH.blok CATCH zaczyna się od instrukcja BEGIN CATCH i kończy instrukcją END CATCH.W Transact-SQL, każdy blok TRY jest skojarzony z tylko jednego bloku CATCH.

Praca z TRY…CATCH

Korzystając z konstrukcji TRY…CATCH, należy wziąć pod uwagę następujące wytyczne i wskazówki:

  • Każdą konstrukcję TRY…CATCH musi znajdować się w jednej partia, procedura przechowywana lub wyzwalacza.Na przykład, można umieścić TRY blokowanie w jednej partia i skojarzonym CATCH blokowanie w innej instancji. Poniższy skrypt może wygenerować błąd:

    BEGIN TRY
        SELECT *
            FROM sys.messages
            WHERE message_id = 21;
    END TRY
    GO
    -- The previous GO breaks the script into two batches,
    -- generating syntax errors. The script runs if this GO
    -- is removed.
    BEGIN CATCH
        SELECT ERROR_NUMBER() AS ErrorNumber;
    END CATCH;
    GO
    
  • Blok TRY musi następować bezpośrednio przez bloku CATCH.

  • Konstrukcje TRY…CATCH mogą być zagnieżdżane.Oznacza to, że konstrukcje TRY…CATCH może być umieszczony wewnątrz innych bloków TRY i CATCH.Gdy wystąpi błąd bloku TRY zagnieżdżone, formant programu jest przenoszona do bloku CATCH, która jest skojarzona z zagnieżdżony blok TRY.

  • Do obsługi błędu, który występuje w ramach danego blok CATCH, napisz blok CATCH... TRY… w ramach określonego blok CATCH.

  • Błędy, które ma wskaźnik ważności dla 20 lub większa tego przyczyną Database Engine Aby zamknąć połączenie będzie nie być obsługiwane przez blok TRY…CATCH. Jednak TRY…CATCH obsługiwać błędy ważności 20 lub wyższym, dopóki połączenie nie jest zamknięty.

  • Błędy, które ma wskaźnik ważności dla 10 lub niższym są uważane za ostrzeżenia lub komunikaty informacyjne, a nie są obsługiwane przez TRY…CATCH bloków.

  • Attentions zakończy zadanie partia, nawet jeżeli znajduje się w tej instancji zakres konstrukcji TRY…CATCH.Obejmuje to wiadomości wysłane przez Microsoft Koordynator transakcja rozproszona (MS DTC) podczas transakcja rozproszona nie powiedzie się. Usługa MS DTC zarządza transakcjami rozproszonymi.

    Uwaga

    Jeśli transakcja rozproszona jest wykonywany w ramach zakres z TRY blok wystąpi błąd, wykonywanie jest przenoszone do skojarzonych blok CATCH.Transakcja rozproszona przejdzie w stan niemożliwy do zatwierdzenia.Wykonanie w blok CATCH może zostać przerwane przez Microsoft Koordynator transakcja rozproszona które zarządza transakcja rozproszona. W przypadku wystąpienia błędu usługi MS DTC asynchronicznie powiadamia użytkownika, wszystkie serwery biorących udział w transakcja rozproszona, a kończy wszystkie zadania biorących udział w transakcja rozproszona.To powiadomienie jest wysyłane w postaci uwagi, który nie jest obsługiwany przez konstrukcja TRY…CATCH i partia towaru zostaje zakończona.Po zakończeniu partia wykonywania, Database Engine powoduje powrót wszystkich aktywnych transakcji niemożliwy do zatwierdzenia. Jeśli żaden komunikat o błędzie nie została wysłana transakcja wprowadzenia niemożliwy do zatwierdzenia stan, po zakończeniu partia, komunikat o błędzie zostanie wysłana do aplikacji klienckiej, wskazujący, że transakcja niemożliwy do zatwierdzenia został wykryty i przywrócenie więcej informacji o transakcjach rozproszonych, zobacz Distributed Transactions (Database Engine).

Błąd funkcji

TRY…CATCH używa następujących funkcji błędu do przechwytywania informacji o błędzie:

  • ERROR_NUMBER() zwraca numer błędu.

  • ERROR_MESSAGE() zwraca pełny tekst komunikatu o błędzie.Tekst zawiera wartości, podany dla wszystkich wymiennych parametrów, takich jak długości nazw obiektów i czas.

  • ERROR_SEVERITY() zwraca wagę błędu.

  • ERROR_STATE() zwraca numer stanu błędu.

  • ERROR_LINE() zwraca numer wiersza wewnątrz procedury, która spowodowała błąd.

  • ERROR_PROCEDURE() zwraca nazwę procedura przechowywana lub wyzwalacza, w którym wystąpił błąd.

Informacje o błędach są pobierane za pomocą tych funkcji z dowolnego miejsca w blok CATCH konstrukcji TRY…CATCH zakres.Błąd funkcji zwróci wartość NULL, jeśli o nazwie poza zakresem blok CATCH.Błąd funkcji można odwoływać się w procedurze przechowywanej i mogą być używane do pobierania informacji o błędzie, gdy procedura przechowywana jest wykonywana w blok CATCH.Dzięki temu nie trzeba powtórzyć obsługi w każdym blok CATCH błędów.W przykładzie kodu wykonaj SELECT w instrukcja TRY Blok wygeneruje błąd dzielenia przez zero. Ten błąd będzie obsługiwany przez CATCH blok, który używa procedura przechowywana do zwracania informacji o błędzie.

USE AdventureWorks;
GO

-- Verify that the stored procedure does not exist.
IF OBJECT_ID ('usp_GetErrorInfo', 'P') IS NOT NULL
    DROP PROCEDURE usp_GetErrorInfo;
GO

-- Create a procedure to retrieve error information.
CREATE PROCEDURE usp_GetErrorInfo
AS
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() as ErrorState,
        ERROR_PROCEDURE() as ErrorProcedure,
        ERROR_LINE() as ErrorLine,
        ERROR_MESSAGE() as ErrorMessage;
GO

BEGIN TRY
    -- Generate divide-by-zero error.
    SELECT 1/0;
END TRY
BEGIN CATCH
    -- Execute the error retrieval routine.
    EXECUTE usp_GetErrorInfo;
END CATCH;
GO

Kompilacji i zestawienie-poziom kompilację błędy

Istnieją dwa typy błędów, które nie będzie obsługiwany przez TRY…CATCH, jeśli wystąpi błąd, w tym samym wykonanie poziom jako konstrukcja TRY…CATCH:

  • Skompiluj błędów, takich jak błędy składni, które uniemożliwiają wykonywanie zadanie partia.

  • Błędy, które występują podczas ponownej kompilacji instrukcja poziom, takich jak obiektu nazwę rozwiązania błędów, które się tak zdarzyć po kompilacji ze względu na rozpoznawanie nazw odroczonego.

Podczas partia, procedura przechowywana lub wyzwalacz, który zawiera konstrukcja TRY…CATCH generuje jedno z tych błędów, konstrukcja TRY…CATCH nie obsługuje tych błędów.Te błędy powróci do aplikacji lub partia, o nazwie procedury generuje błąd.Na przykład, następujący kod przykładzie SELECT instrukcja powoduje, że błąd składni. Jeśli ten kod jest wykonywany w SQL Server Management Studio Edytor kwerend wykonanie nie będzie uruchomiony, ponieważ partia nie można skompilować. Błąd zostanie zwrócony Edytor kwerend i nie będzie uzyskać objęte TRY…CATCH.

USE AdventureWorks;
GO

BEGIN TRY
    -- This PRINT statement will not run because the batch
    -- does not begin execution.
    PRINT N'Starting execution';

    -- This SELECT statement contains a syntax error that
    -- stops the batch from compiling successfully.
    SELECT ** FROM HumanResources.Employee;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

W odróżnieniu od błąd składni w poprzednim przykładzie, błąd, który występuje podczas instrukcja-poziom ponownej kompilacji nie przeszkodzi partia kompilacji, ale zostanie zakończona partia, tak szybko, jak ponownej kompilacji dla instrukcja nie powiedzie się.Na przykład jeśli zadanie partia ma dwie instrukcje, a druga instrukcja odwołuje się do tabela, która nie istnieje, odroczone nazw powoduje, że wsadowego pomyślnie skompilować i uruchomić wykonywanie bez wiązanie brakuje tabela planu kwerend, dopóki nie jest ponownie kompilowana tej instrukcji.Partia Zatrzymuje uruchomione w momencie jej pobiera do instrukcja, która odwołuje się do brakującego tabela, a następnie zwraca błąd.Ten typ błędu nie będzie obsługiwany przez konstrukcja TRY…CATCH w tym samym poziom wykonania, w którym wystąpił błąd.Poniższy przykład ilustruje to zachowanie.

USE AdventureWorks;
GO

BEGIN TRY
    -- This PRINT statement will run because the error
    -- occurs at the SELECT statement.
    PRINT N'Starting execution';

    -- This SELECT statement will generate an object name
    -- resolution error because the table does not exist.
    SELECT * FROM NonExistentTable;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

TRY…CATCH służy do obsługi błędów, które powstaną podczas kompilacji lub ponownej kompilacji poziom instrukcję przez wykonywanie kodu generuje błąd w oddzielnych partia w blok TRY.Na przykład można to zrobić przez wprowadzenie kodu w procedurze przechowywanej lub wykonywania dynamiczne Transact-SQL za pomocą instrukcja sp_executesql.Dzięki temu TRY…CATCH wykryć błąd w wyższe poziom wykonywania niż wystąpienie błędu.Na przykład poniższy kod zawiera procedura przechowywana, która generuje błąd rozpoznawania nazwy obiektu.Wsadowy, który zawiera TRY…CATCH Konstrukcja wykonuje na wyższym poziomie niż procedura przechowywana; a wpadł błąd, który pojawia się na niższym poziomie.

USE AdventureWorks;
GO

-- Verify that the stored procedure does not already exist.
IF OBJECT_ID ('usp_MyError', 'P') IS NOT NULL
    DROP PROCEDURE usp_MyError;
GO

CREATE PROCEDURE usp_MyError
AS
    -- This SELECT statement will generate
    -- an object name resolution error.
    SELECT * FROM NonExistentTable;
GO

BEGIN TRY
    -- Run the stored procedure.
    EXECUTE usp_MyError;
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;
GO

Here is the result set.

ErrorNumber ErrorMessage
----------- ---------------------------------------
208         Invalid object name 'NonExistentTable'.

Aby uzyskać więcej informacji zobacz Deferred Name Resolution and Compilationi w sekcji "Ponownej kompilacji plany wykonanie" Wykonanie planu buforowanie i ponowne użycie.

Transakcje niemożliwy do zatwierdzenia

Wewnątrz konstrukcji TRY…CATCH transakcji, można wprowadzić stan, w którym transakcja pozostaje otwarty, ale nie mogą być zatwierdzane.Transakcja nie może wykonać każdą czynność, którą będzie generować zapisu dziennik transakcji, takie jak modyfikacja danych lub próby przywrócenia punkt bezpieczny.Jednak w tym stanie blokad nabytych przez transakcję są zachowywane, a połączenie również pozostaje otwarty.Skutków transakcji nie są wycofane, dopóki nie wydano instrukcja ROLLBACK lub do partia kończy się i transakcja jest automatycznie przywracana Database Engine. Jeśli żaden komunikat o błędzie nie została wysłana, gdy wprowadzona niemożliwy do zatwierdzenia stan transakcji po zakończeniu pracy partia, do aplikacji klienckiej, która wskazuje wykryto niemożliwy do zatwierdzenia transakcję i wycofane wysyłany jest komunikat o błędzie.

Transakcja przejdzie w stan niemożliwy do zatwierdzenia wewnątrz TRY blok, gdy wystąpi błąd, który będzie w przeciwnym razie zakończyły transakcji.Na przykład, większość błędów z instrukcja danych definicji języka (DDL) (takie jak CREATE tabela) lub większość błędów występujących podczas XACT_ABORT zestaw jest ustawiona na ON, zakończenia transakcji poza blok TRY, ale należy niemożliwy do zatwierdzenia wewnątrz blok TRY transakcji.

Kod w blok CATCH należy przetestować dla stanu transakcji za pomocą funkcja XACT_STATE.XACT_STATE zwraca -1, jeśli sesja ma niemożliwy do zatwierdzenia transakcję.blok CATCH nie musi wykonywać żadnych czynności, które może wygenerować zapis do dziennika, jeśli XACT_STATE zwraca -1.W poniższym przykładzie kodu generuje błąd w instrukcja DDL i używa XACT_STATE Aby sprawdzić stan transakcji w celu uwzględnienia najbardziej odpowiednią akcja.

USE AdventureWorks;
GO

-- Verify that the table does not exist.
IF OBJECT_ID (N'my_books', N'U') IS NOT NULL
    DROP TABLE my_books;
GO

-- Create table my_books.
CREATE TABLE my_books
    (
    Isbn        int PRIMARY KEY,
    Title       NVARCHAR(100)
    );
GO

BEGIN TRY
    BEGIN TRANSACTION;
        -- This statement will generate an error because the 
        -- column author does not exist in the table.
        ALTER TABLE my_books
            DROP COLUMN author;
    -- If the DDL statement succeeds, commit the transaction.
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    SELECT
        ERROR_NUMBER() as ErrorNumber,
        ERROR_MESSAGE() as ErrorMessage;

    -- Test XACT_STATE for 1 or -1.
    -- XACT_STATE = 0 means there is no transaction and
    -- a commit or rollback operation would generate an error.

    -- Test whether the transaction is uncommittable.
    IF (XACT_STATE()) = -1
    BEGIN
        PRINT
            N'The transaction is in an uncommittable state. ' +
            'Rolling back transaction.'
        ROLLBACK TRANSACTION;
    END;

    -- Test whether the transaction is active and valid.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT
            N'The transaction is committable. ' +
            'Committing transaction.'
        COMMIT TRANSACTION;   
    END;
END CATCH;
GO

Obsługa zakleszczenia

TRY…CATCH może służyć do obsługi zakleszczenia.Błąd ofiara zakleszczenie 1205 mogą zostać objęte blok CATCH i może być wycofać transakcji, ponownie, aż zostanie odblokowany wątki.Aby uzyskać więcej informacji na temat deadlocking zobacz Deadlocking.

W poniższym przykładzie pokazano, w jaki sposób TRY…CATCH można użyć do obsługi zakleszczenia.W tej części pierwszego tworzy tabela, która zostanie użyta do wykazania stanu zakleszczenie i procedura przechowywana, które mają być używane do drukowania informacji o błędzie.

USE AdventureWorks;
GO

-- Verify that the table does not exist.
IF OBJECT_ID (N'my_sales',N'U') IS NOT NULL
    DROP TABLE my_sales;
GO

-- Create and populate the table for deadlock simulation.
CREATE TABLE my_sales 
    (
    Itemid       INT PRIMARY KEY,
    Sales        INT not null
    );
GO

INSERT my_sales (itemid, sales) VALUES (1, 1);
INSERT my_sales (itemid, sales) VALUES (2, 1);
GO
  
-- Verify that the stored procedure for error printing
-- does not exist.
IF OBJECT_ID (N'usp_MyErrorLog',N'P') IS NOT NULL
    DROP PROCEDURE usp_MyErrorLog;
GO

-- Create a stored procedure for printing error information.
CREATE PROCEDURE usp_MyErrorLog
AS
    PRINT 
        'Error ' + CONVERT(VARCHAR(50), ERROR_NUMBER()) +
        ', Severity ' + CONVERT(VARCHAR(5), ERROR_SEVERITY()) +
        ', State ' + CONVERT(VARCHAR(5), ERROR_STATE()) + 
        ', Line ' + CONVERT(VARCHAR(5), ERROR_LINE());
    PRINT 
        ERROR_MESSAGE();
GO

Następujące skrypty kodu dla sesja 1 i 2 sesja jednoczesne uruchamianie dwa oddzielne SQL Server Management Studio połączenia. Zarówno sesje podjęta próba zaktualizowania tego samego wierszy w tabela.Jedną z sesja powiedzie się podczas pierwszej próby operacji aktualizacji i innych sesja zostanie wybrany jako ofiara zakleszczenie.Błąd ofiara zakleszczenie spowoduje, że wykonanie przejść do blok CATCH i transakcji wejdzie w stan niemożliwy do zatwierdzenia.Wewnątrz blok CATCH ofiara zakleszczenie można wycofać transakcji, a następnie ponów próbę aktualizacji tabela, aż do chwili, kiedy aktualizacji kończy się pomyślnie lub zostanie osiągnięty limit ponownych prób, zależnie od tego, który stanie się pierwszym.

Sesja 1

Sesja 2

USE AdventureWorks;
GO
-- Declare and set variable
-- to track number of retries
-- to try before exiting.
DECLARE @retry INT;
SET @retry = 5;
-- Keep trying to update 
-- table if this task is 
-- selected as the deadlock 
-- victim.
WHILE (@retry > 0)
BEGIN
    BEGIN TRY
        BEGIN TRANSACTION;
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 1;
        WAITFOR DELAY '00:00:13';
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 2;
        SET @retry = 0;
        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH 
        -- Check error number.
        -- If deadlock victim error,
        -- then reduce retry count
        -- for next update retry. 
        -- If some other error
        -- occurred, then exit
        -- retry WHILE loop.
        IF (ERROR_NUMBER() = 1205)
            SET @retry = @retry - 1;
        ELSE
            SET @retry = -1;
        -- Print error information.
        EXECUTE usp_MyErrorLog;
  
        IF XACT_STATE() <> 0
            ROLLBACK TRANSACTION;
    END CATCH;
END; -- End WHILE loop.
GO
USE AdventureWorks;
GO
-- Declare and set variable
-- to track number of retries
-- to try before exiting.
DECLARE @retry INT;
SET @retry = 5;
--Keep trying to update 
-- table if this task is 
-- selected as the deadlock 
-- victim.
WHILE (@retry > 0)
BEGIN
    BEGIN TRY
       BEGIN TRANSACTION;
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 2;
        WAITFOR DELAY '00:00:07';
    
        UPDATE my_sales
        SET sales = sales + 1
        WHERE itemid = 1;
        SET @retry = 0;
        COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH 
        -- Check error number.
        -- If deadlock victim error,
        -- then reduce retry count
        -- for next update retry. 
        -- If some other error
        -- occurred, then exit
        -- retry WHILE loop.
        IF (ERROR_NUMBER() = 1205)
            SET @retry = @retry - 1;
        ELSE
            SET @retry = -1;
        -- Print error information.
        EXECUTE usp_MyErrorLog;
  
        IF XACT_STATE() <> 0
            ROLLBACK TRANSACTION;
    END CATCH;
END; -- End WHILE loop.
GO

TRY…CATCH o instrukcji RAISERROR

RAISERROR można używać w blok TRY lub CATCH konstrukcji TRY…CATCH wpływ na zachowanie obsługi błędów.

RAISERROR, który ma ważności 11-19 wykonywane wewnątrz blok TRY powoduje, że formant do skojarzonego blok CATCH.RAISERROR, który ma ważności 11-19 wykonywane wewnątrz blok CATCH zwraca błąd, do wywołującego aplikacji lub partia.W ten sposób RAISERROR może służyć do zwracania informacji do obiektu wywołującego o błąd, który spowodował blok CATCH do wykonać.Błąd informacji dostarczanych przez funkcje o TRY…CATCH mogą być przechwytywane RAISERROR komunikatu, po czym oryginalny numer błędu; jednak musi to być numer błędu dla RAISERROR >= 50 000.

RAISERROR, który ma wskaźnik ważności dla 10 lub niższym zwraca komunikat informacyjny, do wywołującego partia lub aplikacji bez wywoływania blok CATCH.

RAISERROR, który ma wskaźnik ważności, 20 i wyższe zamyka połączenie z bazą danych bez wywoływania blok CATCH.

Następujący kod jak pokazano w przykładzie RAISERROR może być używana wewnątrz CATCH blok, aby przywrócić oryginalne informacje o wywołującym aplikację lub partia. Procedura przechowywana usp_GenerateError wykonuje DELETE Instrukcja wewnątrz TRY blok, który generuje błąd naruszenia zasad do ograniczenia. Błąd powoduje, że wykonanie do skojarzonym CATCH blok wewnątrz usp_GenerateError w przypadku gdy procedura przechowywana usp_RethrowError zostanie wykonana podnieść, używając informacji o naruszenie ograniczenia RAISERROR. Ten błąd, generowany przez RAISERROR jest zwracany do wywołującej partia w przypadku gdy usp_GenerateError Wykonano i powoduje, że wykonanie do skojarzonym CATCH Zablokuj wywołania partia.

Uwaga

RAISERROR mogą generować błędy ze stanem od 1 do 127 tylko.Ponieważ Database Engine być może podnieść błędy ze stanem 0, zaleca się sprawdzenie stanu błędu zwrócony przez ERROR_STATE przed przekazaniem go jako wartość parametru stanu RAISERROR.

USE AdventureWorks;
GO

-- Verify that stored procedure does not exist.
IF OBJECT_ID (N'usp_RethrowError',N'P') IS NOT NULL
    DROP PROCEDURE usp_RethrowError;
GO

-- Create the stored procedure to generate an error using 
-- RAISERROR. The original error information is used to
-- construct the msg_str for RAISERROR.
CREATE PROCEDURE usp_RethrowError AS
    -- Return if there is no error information to retrieve.
    IF ERROR_NUMBER() IS NULL
        RETURN;

    DECLARE 
        @ErrorMessage    NVARCHAR(4000),
        @ErrorNumber     INT,
        @ErrorSeverity   INT,
        @ErrorState      INT,
        @ErrorLine       INT,
        @ErrorProcedure  NVARCHAR(200);

    -- Assign variables to error-handling functions that 
    -- capture information for RAISERROR.
    SELECT 
        @ErrorNumber = ERROR_NUMBER(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE(),
        @ErrorLine = ERROR_LINE(),
        @ErrorProcedure = ISNULL(ERROR_PROCEDURE(), '-');

    -- Build the message string that will contain original
    -- error information.
    SELECT @ErrorMessage = 
        N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 
            'Message: '+ ERROR_MESSAGE();

    -- Raise an error: msg_str parameter of RAISERROR will contain
    -- the original error information.
    RAISERROR 
        (
        @ErrorMessage, 
        @ErrorSeverity, 
        1,               
        @ErrorNumber,    -- parameter: original error number.
        @ErrorSeverity,  -- parameter: original error severity.
        @ErrorState,     -- parameter: original error state.
        @ErrorProcedure, -- parameter: original error procedure name.
        @ErrorLine       -- parameter: original error line number.
        );
GO

-- Verify that stored procedure does not exist.
IF OBJECT_ID (N'usp_GenerateError',N'P') IS NOT NULL
    DROP PROCEDURE usp_GenerateError;
GO

-- Create a stored procedure that generates a constraint violation
-- error. The error is caught by the CATCH block where it is 
-- raised again by executing usp_RethrowError.
CREATE PROCEDURE usp_GenerateError 
AS 
    BEGIN TRY
        -- A FOREIGN KEY constraint exists on the table. This 
        -- statement will generate a constraint violation error.
        DELETE FROM Production.Product
            WHERE ProductID = 980;
    END TRY
    BEGIN CATCH
        -- Call the procedure to raise the original error.
        EXEC usp_RethrowError;
    END CATCH;
GO

-- In the following batch, an error occurs inside 
-- usp_GenerateError that invokes the CATCH block in
-- usp_GenerateError. RAISERROR inside this CATCH block
-- generates an error that invokes the outer CATCH
-- block in the calling batch.
BEGIN TRY  -- outer TRY
    -- Call the procedure to generate an error.
    EXECUTE usp_GenerateError;
END TRY
BEGIN CATCH  -- Outer CATCH
    SELECT
        ERROR_NUMBER() as ErrorNumber,
        ERROR_MESSAGE() as ErrorMessage;
END CATCH;
GO

Zmiana przepływu wykonanie

Aby zmienić przepływem wykonania, GOTO mogą być używane wewnątrz blok TRY lub blok CATCH.GOTO mogą również służyć do zakończenia blok TRY lub blok CATCH; jednak GOTO nie można używać do wprowadzania blok TRY lub blok CATCH.

Rozwiązanie do obsługi błędu AdventureWorks przykładowej bazy danych

The AdventureWorks sample database includes an error-handling solution designed to log information about errors that are caught by the CATCH blok of a TRY…CATCH construct that can later be queried or analyzed.

dbo.ErrorLog tabela

The ErrorLog tabela records information about an error number, error severity, error state, name of the procedura przechowywana or trigger where the error occurred, line number at which the error occurred, and the complete text of the error message.Rejestruje także data i czas, w którym wystąpił błąd i nazwę użytkownika, które są wykonywane rutynowo generuje błąd.Ta tabela jest pusta, gdy procedura przechowywana uspLogError jest wykonywany w zakresie blok CATCH konstrukcji TRY…CATCH.Aby uzyskać więcej informacji zobaczTabela ErrorLog (AdventureWorks).

dbo.uspLogError

Procedura przechowywana uspLogError zalogowaniu informacje o błędachErrorLog tabela o błędzie, który spowodował wykonanie do blok CATCH konstrukcji TRY…CATCH.Dla uspLogError , aby wstawić informacje o błędach do ErrorLog tabela, muszą istnieć następujące warunki:

  • uspLogError jest wykonywany w ramach zakres blok CATCH.

  • Jeśli bieżąca transakcja jest w stanie niemożliwy do zatwierdzenia, transakcja jest cofana przed wykonaniem uspLogError.

Parametr wyjściowy @ ErrorLogID of uspLogError z zwraca wartośćErrorLogID za pomocą wierszauspLogError into the ErrorLog tabela.Wartość domyślna @ ErrorLogID is 0.W poniższym przykładzie pokazano kod uspLogError. Aby uzyskać więcej informacji zobaczProcedury przechowywanej w AdventureWorks.

CREATE PROCEDURE [dbo].[uspLogError] 
    @ErrorLogID [int] = 0 OUTPUT  -- Contains the ErrorLogID of the row inserted
                                  -- by uspLogError in the ErrorLog table.

AS
BEGIN
    SET NOCOUNT ON;

    -- Output parameter value of 0 indicates that error 
    -- information was not logged.
    SET @ErrorLogID = 0;

    BEGIN TRY
        -- Return if there is no error information to log.
        IF ERROR_NUMBER() IS NULL
            RETURN;

        -- Return if inside an uncommittable transaction.
        -- Data insertion/modification is not allowed when 
        -- a transaction is in an uncommittable state.
        IF XACT_STATE() = -1
        BEGIN
            PRINT 'Cannot log error since the current transaction is in an uncommittable state. ' 
                + 'Rollback the transaction before executing uspLogError in order to successfully log error information.';
            RETURN;
        END;

        INSERT [dbo].[ErrorLog] 
            (
            [UserName], 
            [ErrorNumber], 
            [ErrorSeverity], 
            [ErrorState], 
            [ErrorProcedure], 
            [ErrorLine], 
            [ErrorMessage]
            ) 
        VALUES 
            (
            CONVERT(sysname, CURRENT_USER), 
            ERROR_NUMBER(),
            ERROR_SEVERITY(),
            ERROR_STATE(),
            ERROR_PROCEDURE(),
            ERROR_LINE(),
            ERROR_MESSAGE()
            );

        -- Pass back the ErrorLogID of the row inserted
        SELECT @ErrorLogID = @@IDENTITY;
    END TRY
    BEGIN CATCH
        PRINT 'An error occurred in stored procedure uspLogError: ';
        EXECUTE [dbo].[uspPrintError];
        RETURN -1;
    END CATCH
END; 

dbo.uspPrintError

The stored procedure uspPrintError prints information about the error that caused execution to transfer to the CATCH block of a TRY…CATCH construct.uspPrintError should be executed in the scope of a CATCH block; otherwise, the procedure returns without printing any error information.W poniższym przykładzie pokazano kod uspPrintError. Aby uzyskać więcej informacji zobaczProcedury przechowywanej w AdventureWorks.

CREATE PROCEDURE [dbo].[uspPrintError] 
AS
BEGIN
    SET NOCOUNT ON;

    -- Print error information. 
    PRINT 'Error ' + CONVERT(varchar(50), ERROR_NUMBER()) +
          ', Severity ' + CONVERT(varchar(5), ERROR_SEVERITY()) +
          ', State ' + CONVERT(varchar(5), ERROR_STATE()) + 
          ', Procedure ' + ISNULL(ERROR_PROCEDURE(), '-') + 
          ', Line ' + CONVERT(varchar(5), ERROR_LINE());
    PRINT ERROR_MESSAGE();
END;

Przykład obsługa błędów

W poniższym przykładzie zademonstrowano AdventureWorks rozwiązanie do obsługi błędów. Kod wewnątrz TRY Blok próbuje usunąć rekordu z ProductID 980 w Production.Product Tabela. Zapobiega ograniczenia klucz obcy dla tabela DELETE generowania sprawozdania z kolejnego i błąd naruszenia zasad do ograniczenia. Błąd ten powoduje, że wykonanie do CATCH blok. Wewnątrz CATCH blokowanie, zachodzą następujące akcje:

  • uspPrintError Umożliwia drukowanie informacji o błędzie.

  • Po transakcja jest cofana, uspLogError wprowadza informacje o błędzie w ErrorLog Tabela i zwraca ErrorLogID wstawionego wiersza na @ErrorLogID OUTPUT parametr.

USE AdventureWorks;
GO

-- Variable to store ErrorLogID value of the row
-- inserted in the ErrorLog table by uspLogError 
DECLARE @ErrorLogID INT;

BEGIN TRY
    BEGIN TRANSACTION;

    -- A FOREIGN KEY constraint exists on this table. This 
    -- statement will generate a constraint violation error.
    DELETE FROM Production.Product
        WHERE ProductID = 980;

    -- If the delete operation succeeds, commit the transaction.
    COMMIT TRANSACTION;
END TRY
BEGIN CATCH
    -- Call procedure to print error information.
    EXECUTE dbo.uspPrintError;

    -- Roll back any active or uncommittable transactions before
    -- inserting information in the ErrorLog.
    IF XACT_STATE() <> 0
    BEGIN
        ROLLBACK TRANSACTION;
    END

    EXECUTE dbo.uspLogError @ErrorLogID = @ErrorLogID OUTPUT;
END CATCH; 

-- Retrieve logged error information.
SELECT * FROM dbo.ErrorLog WHERE ErrorLogID = @ErrorLogID;
GO

Zagnieżdżone przykład obsługi błędów

W poniższym przykładzie pokazano, przy użyciu konstrukcji TRY…CATCH zagnieżdżonych.

BEGIN TRY
    BEGIN TRY
        SELECT CAST('invalid_date' AS datetime)
    END TRY
    BEGIN CATCH 
        PRINT 'Inner TRY error number: ' +    
            CONVERT(varchar,ERROR_NUMBER()) + ' on line: ' +
            CONVERT(varchar, ERROR_LINE())
    END CATCH
    SELECT CAST('invalid_int' AS int)
END TRY
BEGIN CATCH
    PRINT 'Outer TRY error mumber: ' + CONVERT(varchar,ERROR_NUMBER())+ 
            ' on line: ' + CONVERT(varchar, ERROR_LINE())
END CATCH

Here is the result set.

Inner TRY error number: 241 on line: 3

Outer TRY error number: 245 on line: 9