다음을 통해 공유


TRY...CATCH(Transact-SQL)

적용 대상: SQL Server Azure SQL Database Azure SQL Managed Instance Azure Synapse Analytics Analytics Platform System(PDW) Microsoft Fabric의 SQL 분석 엔드포인트 Microsoft Fabric의 웨어하우스

C# 및 Visual C++ 언어의 예외 처리와 유사한 Transact-SQL에 대한 오류 처리를 구현합니다. Transact-SQL 문 그룹은 블록으로 TRY 묶을 수 있습니다. 블록에서 TRY 오류가 발생하면 컨트롤은 일반적으로 블록으로 묶 CATCH 인 다른 문 그룹에 전달됩니다.

Transact-SQL 구문 표기 규칙

구문

BEGIN TRY
    { sql_statement | statement_block }
END TRY
BEGIN CATCH
    [ { sql_statement | statement_block } ]
END CATCH
[ ; ]

인수

sql_statement

Transact-SQL 문입니다.

statement_block

일괄 처리 또는 블록으로 묶 BEGIN...END 인 Transact-SQL 문의 모든 그룹입니다.

설명

구문은 TRY...CATCH 데이터베이스 연결을 닫지 않는 심각도가 10보다 높은 모든 실행 오류를 catch합니다.

TRY 블록 바로 뒤에 연결된 CATCH 블록이 있어야 합니다. 문과 BEGIN CATCH 문 사이에 END TRY 다른 문을 포함하면 구문 오류가 발생합니다.

구문은 TRY...CATCH 여러 일괄 처리에 걸쳐 있지 않습니다. 구문은 TRY...CATCH Transact-SQL 문의 여러 블록에 걸쳐 있지 않습니다. 예를 들어 구문은 TRY...CATCH Transact-SQL 문의 두 BEGIN...END 블록에 걸쳐 있지 않으며 구문을 확장 IF...ELSE 할 수 없습니다.

블록에 묶 TRY 인 코드에 오류가 없는 경우 블록의 마지막 문이 TRY 완료되면 연결된 END CATCH 문 바로 다음에 컨트롤이 문으로 전달됩니다.

블록에 묶 TRY 인 코드에 오류가 있으면 컨트롤이 연결된 CATCH 블록의 첫 번째 문으로 전달됩니다. 블록의 코드가 CATCH 완료되면 제어가 문 바로 다음 문으로 END CATCH 전달됩니다.

참고 항목

END CATCH 문이 저장 프로시저 또는 트리거의 마지막 문인 경우 컨트롤은 저장 프로시저를 호출하거나 트리거를 발생시킨 문으로 다시 전달됩니다.

블록에 의해 CATCH 트래핑된 오류는 호출 애플리케이션에 반환되지 않습니다. 오류 정보의 일부를 애플리케이션에 반환해야 하는 경우 블록의 CATCH 코드는 결과 집합 또는 RAISERROR 문과 PRINT 같은 SELECT 메커니즘을 사용하여 반환해야 합니다.

TRY...CATCH 구문을 중첩할 수 있습니다. TRY 블록 또는 블록은 CATCH 중첩된 TRY...CATCH 구문을 포함할 수 있습니다. 예를 들어 블록에는 CATCH 코드에서 발생하는 오류를 처리하는 포함된 TRY...CATCH 구문이 CATCH 포함될 수 있습니다.

블록에서 CATCH 발생한 오류는 다른 곳에서 생성된 오류처럼 처리됩니다. 블록에 CATCH 중첩 구 TRY...CATCH 문이 포함된 경우 중첩된 TRY 블록의 오류는 중첩된 CATCH 블록에 컨트롤을 전달합니다. 중첩된 TRY...CATCH 구문이 없으면 오류가 호출자에게 다시 전달됩니다.

TRY...CATCH 는 블록의 코드 TRY 에 의해 실행되는 저장 프로시저 또는 트리거에서 처리되지 않은 오류를 catch합니다. 또는 저장 프로시저 또는 트리거에 코드에서 생성된 오류를 처리하기 위한 자체 TRY...CATCH 구문을 포함할 수 있습니다. 예를 들어 블록이 TRY 저장 프로시저를 실행하고 저장 프로시저에서 오류가 발생하면 다음과 같은 방법으로 오류를 처리할 수 있습니다.

  • 저장 프로시저에 자체 TRY...CATCH 구문이 없는 경우 오류는 문이 포함된 블록과 연결된 블록에 TRY 컨트롤 CATCHEXECUTE 반환합니다.

  • 저장 프로시저에 구문이 TRY...CATCH 포함된 경우 오류는 저장 프로시저의 CATCH 블록으로 컨트롤을 전송합니다. 블록 코드가 CATCH 완료되면 저장 프로시저를 호출한 문 바로 후에 EXECUTE 컨트롤이 문으로 다시 전달됩니다.

GOTO 문을 사용하여 입력 TRY 하거나 CATCH 차단할 수 없습니다. GOTO 문을 사용하여 같은 TRY 레이블 또는 블록 내의 레이블로 이동하거나 CATCH 또는 블록을 떠날 TRY CATCH 수 있습니다.

사용자 정의 함수에서는 구 TRY...CATCH 문을 사용할 수 없습니다.

오류 정보 검색

블록 범위 CATCH 에서 다음 시스템 함수를 사용하여 블록을 실행한 CATCH 오류에 대한 정보를 가져올 수 있습니다.

함수 설명
ERROR_NUMBER 오류 수를 반환합니다.
ERROR_SEVERITY 심각도를 반환합니다.
ERROR_STATE 오류 상태 번호를 반환합니다.
ERROR_PROCEDURE 오류가 발생한 저장 프로시저 또는 트리거의 이름을 반환합니다.
ERROR_LINE 오류를 발생시킨 루틴 내의 줄 번호를 반환합니다.
ERROR_MESSAGE 오류 메시지의 전체 텍스트를 반환합니다. 이 텍스트는 길이, 개체 이름 또는 시간과 같은 대체 가능한 매개 변수에 제공된 값을 포함합니다.

이러한 함수는 블록 범위 외부에서 호출되는 경우 반환 NULL 됩니다 CATCH . 오류 정보는 블록 범위 CATCH 내의 어디에서나 이러한 함수를 사용하여 검색할 수 있습니다. 예를 들어 다음 스크립트는 오류 처리 함수를 포함하는 저장 프로시저를 보여 줍니다. CATCH 구문의 TRY...CATCH 블록에서 이 저장 프로시저를 호출하면 오류에 대한 정보가 반환됩니다.

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

-- Create 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 error retrieval routine.
    EXECUTE usp_GetErrorInfo;
END CATCH;

함수는 ERROR_* 고유하게 컴파일된 저장 프로시저 내의 블록에서도 CATCH 작동합니다.

TRY의 영향을 받지 않는 오류... CATCH 구문

TRY...CATCH 구문은 다음 조건을 트래핑하지 않습니다.

  • 심각도가 10 이하인 경고 또는 정보 메시지

  • 해당 세션에 대한 SQL Server 데이터베이스 엔진 태스크 처리를 중지하게 만드는 심각도 20 이상의 오류. 심각도가 20 이상이고 데이터베이스 연결이 중단 TRY...CATCH 되지 않는 오류가 발생하면 오류를 처리합니다.

  • 클라이언트 인터럽트 요청 또는 클라이언트 연결 끊김과 같은 주의

  • 시스템 관리자가 문을 사용하여 KILL 세션을 종료하는 경우

다음 유형의 오류는 구문과 동일한 실행 수준에서 TRY...CATCH 발생하는 경우 블록에서 처리 CATCH 되지 않습니다.

  • 구문 오류와 같이 일괄 처리의 실행을 막는 컴파일 오류

  • 문 수준 다시 컴파일 단계에서 발생한 오류(예: 컴파일 이후에 지연된 이름 확인으로 발생한 개체 이름 확인 오류)

  • 개체 이름 확인 오류

이런 오류는 해당 일괄 처리, 저장 프로시저 또는 트리거를 실행한 수준으로 반환됩니다.

블록 내에서 TRY 더 낮은 실행 수준(예: 실행 sp_executesql 중 또는 사용자 정의 저장 프로시저)에서 컴파일 또는 문 수준 다시 컴파일 중에 오류가 발생하는 경우 오류는 구문보다 TRY...CATCH 낮은 수준에서 발생하며 연결된 CATCH 블록에서 처리됩니다.

다음 예제에서는 문에서 생성한 개체 이름 확인 오류가 구문에 SELECT 의해 TRY...CATCH catch되지 않고 저장 프로시저 내에서 동일한 SELECT 문이 실행될 때 블록에 의해 CATCH catch되는 방법을 보여 드립니다.

BEGIN TRY
    -- Table does not exist; object name resolution
    -- error not caught.
    SELECT *
    FROM NonexistentTable;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH

오류가 catch되지 않고 컨트롤이 TRY...CATCH 구문에서 다음 상위 수준으로 전달됩니다.

SELECT 저장 프로시저 내에서 문을 실행하면 블록보다 TRY 낮은 수준에서 오류가 발생합니다. 이 오류는 구문에 TRY...CATCH 의해 처리됩니다.

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

-- Create a stored procedure that will cause an
-- object resolution error.
CREATE PROCEDURE usp_ExampleProc
AS
SELECT *
FROM NonexistentTable;
GO

BEGIN TRY
    EXECUTE usp_ExampleProc;
END TRY

BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber,
        ERROR_MESSAGE() AS ErrorMessage;
END CATCH;

커밋할 수 없는 트랜잭션 및 XACT_STATE

블록에서 TRY 생성된 오류로 인해 현재 트랜잭션의 상태가 무효화되면 트랜잭션은 커밋할 수 없는 트랜잭션으로 분류됩니다. 일반적으로 블록 외부 TRY 의 트랜잭션을 종료하는 오류로 인해 블록 내에서 TRY 오류가 발생할 때 트랜잭션이 커밋할 수 없는 상태가 됩니다. 커밋할 수 없는 트랜잭션은 읽기 작업 또는 ROLLBACK TRANSACTION. 트랜잭션은 쓰기 작업 또는 COMMIT TRANSACTION를 생성하는 Transact-SQL 문을 실행할 수 없습니다. 이 함수는 XACT_STATE 트랜잭션이 커밋할 수 없는 트랜잭션으로 분류된 경우의 -1 값을 반환합니다. 일괄 처리가 완료되면 데이터베이스 엔진은 커밋 불가능 활성 트랜잭션을 모두 롤백합니다. 트랜잭션이 커밋할 수 없는 상태가 될 때 오류 메시지가 전송되지 않은 경우 일괄 처리가 완료되면 클라이언트 애플리케이션에 오류 메시지가 전송됩니다. 이 메시지는 커밋 불가능 트랜잭션이 검색되어 롤백되었음을 보여 줍니다.

커밋할 수 없는 트랜잭션 및 XACT_STATE 함수에 대한 자세한 내용은 XACT_STATE 참조하세요.

예제

A. TRY 사용... 잡기

다음 예에서는 0으로 나누기 오류를 일으키는 SELECT 문을 보여 줍니다. 이 오류로 인해 연결된 CATCH 블록으로 실행이 이동합니다.

BEGIN TRY
    -- Generate a divide-by-zero error.
    SELECT 1 / 0;
END TRY

BEGIN CATCH
    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;
END CATCH;
GO

B. TRY 사용... 트랜잭션의 CATCH

다음 예에서는 트랜잭션 내에서 TRY...CATCH 블록이 작동하는 방법을 보여 줍니다. TRY 블록 내의 문은 제약 조건 위반 오류를 일으킵니다.

BEGIN TRANSACTION;

BEGIN TRY
    -- Generate a constraint violation error.
    DELETE
    FROM Production.Product
    WHERE ProductID = 980;
END TRY

BEGIN CATCH
    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;

    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
END CATCH;

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;
GO

C. TRY 사용... CATCH with XACT_STATE

다음 예에서는 트랜잭션 내부에서 발생하는 오류를 TRY...CATCH 구문을 사용하여 처리하는 방법을 보여 줍니다. 트랜잭션을 커밋해야 하는지 또는 롤백해야 하는지는 XACT_STATE 함수가 결정합니다. 이 예에서 SET XACT_ABORTON입니다. 이렇게 하면 제약 조건 위반 오류가 발생할 경우 트랜잭션을 커밋할 수 없습니다.

-- Check to see whether this stored procedure exists.
IF OBJECT_ID(N'usp_GetErrorInfo', N'P') IS NOT NULL
    DROP PROCEDURE usp_GetErrorInfo;
GO

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

-- SET XACT_ABORT ON will cause the transaction to be uncommittable
-- when the constraint violation occurs.
SET XACT_ABORT ON;

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 statement succeeds, commit the transaction.
    COMMIT TRANSACTION;
END TRY

BEGIN CATCH
    -- Execute error retrieval routine.
    EXECUTE usp_GetErrorInfo;

    -- Test XACT_STATE:
    -- If 1, the transaction is committable.
    -- If -1, the transaction is uncommittable and should
    --     be rolled back.
    -- XACT_STATE = 0 means that 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 committable.
    -- You may want to commit a transaction in a catch block if you want to commit changes to statements that ran prior to the error.
    IF (XACT_STATE()) = 1
    BEGIN
        PRINT N'The transaction is committable. Committing transaction.'

        COMMIT TRANSACTION;
    END;
END CATCH;
GO