ASP에서 레코드셋을 다루듯 쿼리문에서 결과 집합을 다룰 때 사용할 수 있는 것이 커서이다.
SELECT문을 실행하여 얻은 결과 집합을 한행씩 루프를 돌리며 처리를 할 수 있다.
DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ] CURSOR FOR select_statement [ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] } ]
DECLARE cursor_name CURSOR [ LOCAL | GLOBAL ] [ FORWARD_ONLY | SCROLL ] [ STATIC | KEYSET | DYNAMIC | FAST_FORWARD ] [ READ_ONLY | SCROLL_LOCKS | OPTIMISTIC ] [ TYPE_WARNING ] FOR select_statement [ FOR UPDATE [ OF column_name [ ,...n ] ] ]
DECLARE는 커서를 선언하는 부분이며 SQL-92 표준 구문과 Transact-SQL 확장 구문을 모두 허용한다.
-- 변수 선언 DECLARE @user_id VARCHAR(20) -- 커서 선언 / 쿼리 지정 DECLARE cur_mem CURSOR READ_ONLY FOR SELECT user_id FROM TB_Member -- 커서 열기 OPEN cur_mem -- 커서에서 데이터 가져오기 FETCH NEXT FROM cur_mem INTO @user_id WHILE @@FETCH_STATUS = 0 begin -- 행별 처리하기 ... -- 커서에서 데이터 가져오기 (다음행) FETCH NEXT FROM cur_mem INTO @user_id end CLOSE cur_mem DEALLOCATE cur_mem
커서를 오픈하면 행 포인터는 커서의 첫 행 위치에 있다. 포인터를 첫 행으로 옮기려면 행을 패치하면 된다.
패치할때 첫번째 인수로는 NEXT | PRIOR | FIRST | LAST 네가지가 있다.
NEXT | PRIOR | FIRST | LAST |
현재 행 바로 다음의 결과 행을 반환한다. NEXT는 기본 커서 반입 옵션이다. | 현재 행 바로 앞의 결과 행을 반환한다. | 커서의 첫 번째 행을 반환하며, 그 행을 현재 행으로 만든다. | 커서의 마지막 행을 반환하며, 그 행을 현재 행으로 만든다. |
패치할때 INTO를 사용하면 가져온 데이터의 열을 지역변수로 가져올 수 있다.
SELECT문의 열 갯수 만큼 콤마 단위로 지정해주어야 하며, 이전에 변수가 선언되어 있어야 한다.
패치 후 @@FETCH_STATUS 값을 체크하여 무한 루프에 빠지지 않도록 해야한다.
@@FETCH_STATUS 값은 0 (성공), -1 (실패), -2 (반입된 행 없음) 값 중 하나를 리턴한다.
커서를 사용한 후에는 CLOSE문을 사용하여 닫아주어야 한다.
CLOSE문 만으로 커서가 완전히 지워진 것은 아니므로 DEALLOCATE 하기 전에는 몇번이고 반복해서 커서를 오픈하고 닫을 수 있다.
사용이 끝나면 DEALLOCATE 문을 사용하여 자원을 해제해준다.
ASP에서 컴포넌트 객체 생성 후 사용했던 메모리를 반환하는 것과 동일한 원리이다.
커서의 유형
유형 | 특징 |
정적커서 | 정적 커서의 전체 결과 집합은 커서가 열릴 때 tempdb에 작성된다. 성능면에서 가장 빠르다. |
동적커서 | 정적커서와 반대개념으로 원 테이블에 대한 모든 수정결과가 커서에 그대로 반영된다. 성능면에서는 가장 나쁘다. |
전진 전용 커서 | 스크롤을 지원하지 않으며 커서의 처음부터 끝까지 순차적인 행 반입만 지원한다. |
키 집합 커서 | 키 집합은 커서가 열릴때 SELECT문으로 한정된 모든 행으로부터 가져온 일련의 키 값이므로 커서가 열릴 때 tempdb에 작성된다. |
참고
저장 프로시저내에서 커서를 쓰면서 저장 프로시저를 재귀호출 하게 될 경우 흔히 겪을 수 있는 오류는 커서명가 이미 사용중이라는 것이다.
커서를 선언할때 LOCAL | GLOBAL을 명시하지 않을 경우는 디폴드가 GLOBAL이므로 이럴때는 LOCAL로 명시적 선언을 해주어야 한다.