안녕하세요. SQLER의 코난 김대우입니다. 
이번 강좌에서는, 9-2. 커서 - 커서 구문을 진행 하겠습니다.


SQLER에서 진행되는, 챗GPT와 함께 배우는 SQL Server 강좌 목록

 

이번에 진행할 강좌는 커서 구문입니다.

 

 

 

TL;DR

커서 구문은 DECLARE, OPEN, FETCH 반복, CLOSE, DEALLOCATE 순서로 진행됩니다. 여러 종류의 커서를 SQL 코드로 설명하고, 각 작업별 주의사항과 수행 방식을 진행합니다.
 


커서 구문 리뷰

이전 강좌에서 우편물과 우편번호 테이블을 이용해 잘 못 기재된 우편번호를 수정하는 작업을 커서를 실행해 해결했습니다. 커서 구문을 좀 더 살펴보도록 하겠습니다.

 

커서 선언

DECLARE 구문을 사용해 커서를 선언합니다.

--커서 선언
DECLARE curMailTask CURSOR FAST_FORWARD
FOR
SELECT mail_idx, mail_num, mail_address FROM Mails;

 

DECLARE CURSOR 구문 정보

DECLARE cursor_name [ INSENSITIVE ] [ SCROLL ] CURSOR   
     FOR select_statement   
     [ FOR { READ ONLY | UPDATE [ OF column_name [ ,...n ] ] } ]  
[;]  
Transact-SQL Extended Syntax  
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 ] ] ]  
[;]  


커서의 종류는 FORWARD_ONLY, READ_ONLY 등의 여러 방식과 조합이 있습니다. 제가 선언한 FAST_FORWARD는 FORWARD_ONLY와 READ_ONLY 조합이 합쳐진 설정으로 빠르게 커서 작업을 수행하는 일반적으로 가장 많이 사용되는(결과셋을 로우 단위로, 시작부터 끝까지 빠르게 전진하면서 작업) 방식입니다.


STATIC, KEYSET 커서는 STATIC은 사용할 데이터를 tempdb에 복사하며, KEYSET은 행과 순서를 고정하고 일부 keyset 정보만 tempdb에 저장하는 방식입니다. 


FAST_FORWARD가 가장 많이 사용됩니다. 하지만, 커서를 세밀하게 제어하고 싶은 경우에는 다른 방법으로 커서를 선언하세요.
이어지는 FOR SELECT 구문은 로우 단위 작업을 수행할 결과셋을 가져오는 SQL 구문을 작성합니다. 이때, 이렇게 컬럼명을 명시하고, 작업에 필요한 컬럼만 리스트 합니다.

 

커서 오픈

--커서 오픈
OPEN curMailTask


커서 오픈 명령을 수행하면, 선언된 SELECT 구문을 실행하고 첫 로우를 포인팅 합니다. 

 

커서 FETCH

--변수 선언
DECLARE @mail_idx INT
DECLARE @mail_num NVARCHAR(3)
DECLARE @mail_address NVARCHAR(6)

DECLARE @fetched_num NVARCHAR(3)

--첫 로우 FETCH
FETCH NEXT FROM curMailTask INTO @mail_idx, @mail_num, @mail_address

 

로우 단위 작업의 컬럼 값을 변수에 담아야 합니다. 개별 컬럼 값을 담을 변수를 선언하고 FETCH를 수행하면, 컬럼 값을 순차대로, FETCH INTO 구문 뒤의 변수에 넣습니다. 

 

커서 작업 루틴

커서 내부에서 실제 작업을 수행하는 핵심 로직입니다.

WHILE @@FETCH_STATUS = 0
BEGIN
    -- FETCH 된 우편물의 우편 주소에 맞춰 우편번호 수정
    SET @fetched_num = (SELECT mail_num FROM MailsNumer WHERE mail_address LIKE @mail_address)
    -- 만약 우편번호 테이블에서 가져온 우편번호와 우편물의 우편번호가 다르면 UPDATE 수행
    IF @fetched_num <> @mail_num
    BEGIN
        UPDATE Mails 
        SET mail_num = @fetched_num
        WHERE mail_idx = @mail_idx
    END

--다음 로우 FETCH - 루프
FETCH NEXT FROM curMailTask INTO @mail_idx, @mail_num, @mail_address
END

 

프로그래밍 언어의 작업과 마찬가지로 반복문 WHILE 구문과 같은, 커서의 모든 로우를 가져올 때까지 수행하는 @@FETCH_STATUS = 0 조건을 이용해 반복문을 수행합니다.


☑️ 챗GPT 활용: 프로그래밍 언어의 반복문 WHILE 구문에 대해서 알려줘


FETCH 할 때 수행되는 @@FETCH_STATUS 값은 아래와 같습니다.


@@FETCH_STATUS 값 

반환 값
설명
0 FETCH 구문 성공
-1 FETCH 구문이 실패했거나 로우가 결과셋 범위를 벗어남
-2 반입된 로우가 없음
-9 커서가 FETCH 작업을 수행하지 않음


반복문은 BEGIN - END 블록 안에서 실행됩니다.


작업의 목표는 우편물의 주소를 “우편번호 테이블”의 주소와 비교해 다르면 UPDATE 해야 합니다. 위의 FETCH 문에 현재 로우의 주소 정보를 @mail_address에 넣었고, 우편번호 테이블에서 @mail_address로 검색해 우편번호를 가져와 @fetched_num 변수에 저장합니다.


우편물 테이블의 우편번호와 다르면, UPDATE 구문을 실행합니다. 업데이트할 값은 우편번호 테이블에서 가져온 우편번호인 @fetched_num이며, 업데이트할 우편물 테이블 로우의 고윳값은 @mail_idx 컬럼 값입니다. 


위 작업 후, 다음 로우를 FETCH 하고 WHILE 반복문을 수행하면서 더 이상 가져올 로우가 없을 때까지 반복하게 됩니다.

 

커서 CLOSE

--커서 CLOSE
CLOSE curMailTask;

 

커서 작업을 모든 결과셋에 대해 진행하면 커서를 닫습니다. 만약, CLOSE 후 다시 커서를 OPEN 하면 커서는 초기화되어 결과셋의 맨 첫 로우를 다시 포인팅 하게 됩니다.

 

커서 DEALLOCATE

--커서 DEALLOCATE
DEALLOCATE curMailTask;
GO

 

커서가 해제되어 사용하던 모든 커서 리소스가 해제됩니다. 


이렇게 간략히 커서 구문을 확인했습니다. FETCH 작업으로 컬럼의 값을 변수에 담는 작업과, WHILE 블록의 작업이 중요한 부분입니다. 다음 강좌를 진행하기 전체 차근차근 코드를 살펴보시길 바랍니다.
 

 

SQL 강좌 책 구매

강좌가 도움이 되셨다면, 책으로 구매 가능합니다. 책 판매 수익금은 전액 코딩 교육 사회공헌 활동에 기부되며, 아래 링크에서 구매하시면 더 많은 금액이 기부됩니다. 

 

책구매 링크: 챗GPT와 함께하는 마이크로소프트 SQL Server 2022 

책구매링크.png

No. Subject Author Date Views
Notice SQL강좌: 챗GPT와 함께 배우는 SQL Server 무료 강좌 목차와 소개 (2023년 9월 업데이트) 코난(김대우) 2023.08.18 15682
Notice Python 무료 강좌 - 기초, 중급, 머신러닝(2023년 6월 업데이트) 코난(김대우) 2021.01.01 9548
2294 SQL강좌: 12-1. 인덱스 생성과 관리 - 인덱스(Index) 소개 file 코난(김대우) 2023.08.18 43
2293 SQL강좌: 11-8. 관계형 데이터베이스 이해 - 데이터베이스 구현 코난(김대우) 2023.08.18 21
2292 SQL강좌: 11-7. 관계형 데이터베이스 이해 - 데이터베이스 물리적 설계 코난(김대우) 2023.08.18 14
2291 SQL강좌: 11-6. 관계형 데이터베이스 이해 - 데이터베이스 논리적 설계 코난(김대우) 2023.08.18 17
2290 SQL강좌: 11-5. 관계형 데이터베이스 이해 - 데이터베이스 설계 요구사항(Requirements) 분석과 개념적 설계 코난(김대우) 2023.08.18 15
2289 SQL강좌: 11-4. 관계형 데이터베이스 이해 - 데이터베이스 설계 목표와 고려사항 코난(김대우) 2023.08.18 12
2288 SQL강좌: 11-3. 관계형 데이터베이스 이해 - 데이터베이스 설계 단계 file 코난(김대우) 2023.08.18 17
2287 SQL강좌: 11-2. 관계형 데이터베이스 이해 - 데이터베이스 생명주기 file 코난(김대우) 2023.08.18 22
2286 SQL강좌: 11-1. 관계형 데이터베이스 이해 - 관계형 모델 코난(김대우) 2023.08.18 29
2285 SQL강좌: 10-4. T-SQL 프로그래밍 - 공통 테이블 식(CTE-Common Table Expression) 코난(김대우) 2023.08.18 34
2284 SQL강좌: 10-3. T-SQL 프로그래밍 - 변수, 조건문(IF-ELSE), 반복문(WHILE), CASE 표현식 코난(김대우) 2023.08.18 22
2283 SQL강좌: 10-2. T-SQL 프로그래밍 - 일괄처리(Batch) 코난(김대우) 2023.08.18 22
2282 SQL강좌: 10-1. T-SQL 프로그래밍 - 소개 코난(김대우) 2023.08.18 15
2281 SQL강좌: 9-3. 커서 - 현업에서 커서 사용 및 주의사항 코난(김대우) 2023.08.18 46
» SQL강좌: 9-2. 커서 - 커서 구문 코난(김대우) 2023.08.18 21
2279 SQL강좌: 9-1. 커서(CURSOR) - 커서 소개 코난(김대우) 2023.08.18 35
2278 SQL강좌: 8-7. 저장 프로시저 - 프로시저 캐시와 RECOMPILE 코난(김대우) 2023.08.18 31
2277 SQL강좌: 8-6. 저장 프로시저 - 종속성(Dependency) 확인 코난(김대우) 2023.08.18 32
2276 SQL강좌: 8-5. 저장 프로시저 - OUTPUT 파라미터 코난(김대우) 2023.08.18 24
2275 SQL강좌: 8-4. 저장 프로시저 - 동적 SQL(Dynamic SQL)과 SQL 주입(Injection) 공격 코난(김대우) 2023.08.18 38





XE Login