Transact-SQL 커서

Transact-SQL 커서는 주로 다른 Transact-SQL 문에서 사용할 수 있는 결과 집합의 내용을 만드는 Transact-SQL 스크립트, 트리거, 저장 프로시저에서 사용됩니다.

저장 프로시저나 트리거는 일반적으로 다음과 같은 경우에 Transact-SQL 커서를 사용합니다.

  1. Transact-SQL 변수를 선언하여 커서에서 반환한 데이터를 포함합니다. 각 결과 집합 열에 대해 하나의 변수를 선언합니다. 열의 데이터 형식에서 암시적으로 변환할 수 있는 데이터 형식과 열에 의해 반환된 값을 모두 포함할 수 있을 정도의 크기로 변수를 선언합니다.

  2. DECLARE CURSOR 문을 사용하여 Transact-SQL 커서와 SELECT 문을 연결합니다. 또한 DECLARE CURSOR 문은 커서 이름과 커서가 읽기 전용인지 정방향 전용인지의 여부 등 커서 특징도 정의합니다.

  3. OPEN 문을 사용하여 SELECT 문을 실행하고 커서를 채웁니다.

  4. FETCH INTO 문을 사용하여 각 행을 인출하고 각 열의 데이터를 지정한 변수로 옮깁니다. 그러면 다른 Transact-SQL 문이 이 변수를 참조하여 인출된 데이터 값에 액세스할 수 있습니다. Transact-SQL 커서는 행 블록 인출을 지원하지 않습니다.

  5. 커서 작업이 끝나면 CLOSE 문을 사용합니다. 커서를 닫으면 커서의 결과 집합 및 현재 행에 대한 잠금 등의 리소스가 해제되지만 OPEN 문을 다시 실행하면 여전히 처리에 커서 구조를 사용할 수 있습니다. 커서가 계속 표시되므로 이 경우에는 커서 이름을 재사용할 수 없습니다. DEALLOCATE 문은 커서 이름을 포함하여 커서에 할당된 모든 리소스를 완전히 해제합니다. 커서 할당을 취소한 후에는 DECLARE 문을 실행하여 커서를 다시 작성해야 합니다.

Transact-SQL 커서 작업 모니터링

sp_cursor_list 시스템 저장 프로시저를 사용하여 현재 연결에서 볼 수 있는 커서 목록을 가져올 수 있으며 sp_describe_cursor, sp_describe_cursor_columnssp_describe_cursor_tables 시스템 저장 프로시저를 사용하여 커서 특성을 결정할 수 있습니다.

커서가 열린 후에는 sp_cursor_list 또는 sp_describe_cursor가 반환한 @@CURSOR_ROWS 함수나 cursor_rows 열이 커서의 행 수를 나타냅니다.

각 FETCH 문 뒤에 오는 @@FETCH_STATUS는 업데이트되어 마지막 인출 상태를 반영합니다. 또한 sp_describe_cursor에서 반환된 fetch_status 열에서 이 상태 정보를 가져올 수도 있습니다. @@FETCH_STATUS는 커서에서 첫 번째 또는 마지막 행 너머를 인출하는 등의 상황을 보고합니다. @@FETCH_STATUS는 연결에 대해 전역적이며 연결에 대해 열린 커서에서 인출할 때마다 다시 설정됩니다. 나중에 상태를 알아야 할 때는 @@FETCH_STATUS를 사용자 변수에 저장한 다음 연결에 대해 다른 문을 실행합니다. 다음 문에 FETCH를 사용할 수는 없어도 @@FETCH_STATUS를 다시 설정하는 FETCH 문을 포함하는 트리거를 시작하는 INSERT, UPDATE 또는 DELETE를 사용할 수는 있습니다. sp_describe_cursor에서 반환한 fetch_status 열은 지정한 커서에만 해당되며 다른 커서를 참조하는 FETCH 문에 의해서는 영향을 받지 않습니다. 그러나 sp_describe_cursor는 같은 커서를 참조하는 FETCH 문에 의해 영향을 받으므로 주의해야 합니다.

FETCH가 완료되고 나면 커서가 인출한 행에 위치하게 됩니다. 인출된 행을 현재 행이라고 합니다. 커서를 읽기 전용 커서로 선언하지 않으면 UPDATE 또는 DELETE 문을 WHERE CURRENT OF cursor_name 절과 함께 실행하여 현재 행을 수정할 수 있습니다.

DECLARE CURSOR 문에 의해 Transact-SQL 커서에 지정된 이름은 전역적이거나 지역적입니다. 전역 커서 이름은 같은 연결에서 실행되는 모든 일괄 처리, 저장 프로시저 또는 트리거에 의해 참조됩니다. 로컬 커서 이름은 커서가 선언된 일괄 처리, 저장 프로시저 또는 트리거 밖에서는 참조할 수 없습니다. 따라서 트리거 및 저장 프로시저의 로컬 커서는 저장 프로시저나 트리거 밖에서 참조할 수 없습니다.

커서 변수 사용

Microsoft SQL Server에서는 cursor 데이터 형식의 변수도 지원합니다. 다음과 같은 두 가지 방법을 사용하여 커서와 cursor 변수를 연결할 수 있습니다.

/* Use DECLARE @local_variable, DECLARE CURSOR and SET. */
DECLARE @MyVariable CURSOR;

DECLARE MyCursor CURSOR FOR
SELECT LastName FROM AdventureWorks2008R2.Person.Person;

SET @MyVariable = MyCursor;
GO
/* Use DECLARE @local_variable and SET */
DECLARE @MyVariable CURSOR;

SET @MyVariable = CURSOR SCROLL KEYSET FOR
SELECT LastName FROM AdventureWorks2008R2.Person.Person;
DEALLOCATE MyCursor;

커서를 cursor 변수와 연결하고 나면 Transact-SQL 커서 문에서 커서 이름 대신 cursor 변수를 사용할 수 있습니다. 저장 프로시저 출력 매개 변수를 cursor 데이터 형식에 할당하고 커서와 연결할 수도 있습니다. 이렇게 하면 저장 프로시저가 제어된 방법으로 로컬 커서를 표시할 수 있습니다.

Transact-SQL 커서 참조

Transact-SQL 커서 이름 및 변수는 Transact-SQL 문에서만 참조하며 OLE DB, ODBC 및 ADO와 같은 API 함수에서는 참조할 수 없습니다. 예를 들어 DECLARE CURSOR 및 OPEN Transact-SQL 커서를 사용하면 ODBC SQLFetch 또는 SQLFetchScroll 함수를 사용하여 Transact-SQL 커서에서 행을 인출할 수 없습니다. 커서 처리가 필요하고 이러한 API를 사용하는 응용 프로그램은 Transact-SQL 커서 대신 데이터베이스 API에 내장된 커서 지원을 사용해야 합니다.

FETCH를 사용하고 FETCH에서 반환된 각 열을 프로그램 변수에 바인딩하여 응용 프로그램에서 Transact-SQL 커서를 사용할 수 있습니다. 그러나 Transact-SQL FETCH는 일괄 처리를 지원하지 않으므로 응용 프로그램으로 데이터를 반환할 때 효율성이 떨어집니다. 각 행을 인출하려면 서버 왕복이 필요합니다. 일괄 행 인출을 지원하는 데이터베이스 API 내장 커서 기능을 사용하는 것이 더 효율적입니다.

Transact-SQL 커서를 저장 프로시저 및 트리거에 포함하면 매우 효율적입니다. 이렇게 하면 모든 항목이 서버에 있는 하나의 실행 계획으로 컴파일되므로 행 인출과 관련한 네트워크 트래픽이 없기 때문입니다.

Transact-SQL 커서 및 SET 옵션

SQL Server에서는 커서가 열려 있을 때 값이 변경된 경우 FETCH 문을 실행하면 오류가 발생합니다. 이 오류는 다음과 같은 계획에 영향을 주는 옵션이나 인덱싱된 뷰와 계산 열에 필요한 옵션에 대해 발생합니다. 오류를 피하려면 커서가 열린 동안 SET 옵션을 변경하지 마십시오.

옵션에 영향을 주는 계획

ARITHABORT

NUMERIC_ROUNDABORT

FORCEPLAN

QUOTED_IDENTIFIER

ANSI_NULL_DFLT_ON

ANSI_NULL_DFLT_OFF

ANSI_WARNINGS

ANSI_PADDING

ANSI_NULLS

CONCAT_NULL_YIELDS_NULL

DATEFIRST

DATEFORMAT

LANGUAGE

TEXTSIZE

인덱싱된 뷰 및 계산 열

ANSI_NULLS

ANSI_PADDING

ANSI_WARNINGS

ARITHABORT(호환성 수준 80 이하)

CONCAT_NULL_YIELDS_NULL

QUOTED_IDENTIFIER

NUMERIC_ROUNDABORT

SQL Server 2000에서는 다른 옵션과 달리 ANSI_NULLS 및 QUOTED_IDENTIFIER를 변경하더라도 오류가 발생하지 않았습니다.