Intro
안녕하세요.
초보 DBA 다뉴입니다.
처음 Database로 업무를 하고 제일 많이 사용했던 것이 오늘 소개할 커서라는 것 인거 같은데요.
나중에 알고보니 커서를 사용하기에 느려지는 트랜잭션들이 많다는 것을 알게되고,
최대한 줄이려고 노력한 것도 이 커서입니다.
하지만 필요할 때 사용해야 하는 커서(cursor)에 대해서 알아두면 좋으니 한번 알아보도록 하죠.
Cursor
커서(Cursor) 란?
커서는 데이터의 처리를 집합단위가 아닌 행 (ROW)단위로 처리하기 위해 사용합니다.
일종의 반복문이죠.
데이터를 행단위로 처리하기에 행단위 작업에 대한 장점이 있지만,
일괄 처리를 하지않고 각 행의 조회, 처리, 커밋 등의 단위작업이 포함되게 되므로 속도가 느려질 수 있습니다.
BOF (Begin Of File) : 파일의 시작 |
ROW1 |
ROW2 |
ROW3 |
.... |
EOF (End Of File) : 파일의 끝 |
커서는 기본적으로 BOF ~ EOF 까지 커서를 이동하며 행단위의 처리를 합니다.
커서(CURSOR) 사용법
MsSQL의 커서는 아래와 같이 선언하여 사용합니다.
DECLARE Cursor_Name CURSOR
FOR select * from TBTestTable
OPEN Cursor_Name
FETCH NEXT FROM Cursor_Name
INTO @column1, @column2 ...
CLOSE Cursor_Name
DEALLOCATE Cursor_Name
DECLARE [커서이름] CURSOR : [커서이름]의 커서를 선언
FOR [쿼리] : 커서가 바라볼 쿼리를 작성
OPEN [커서이름] : 사용할 커서를 오픈
FETCH NEXT FROM [커서이름] : 오픈된 커서의 다음행을 읽음
INTO [변수1], [변수2] ... : 읽어온 행의 컬럼을 변수에 담는다. (읽어올 컬럼 개수만큼 변수 선언 및 지정)
CLOSE [커서이름] : 사용한 커서를 닫음
DEALLOCATE [커서이름] : 커서 제거
Cursor 활용의 예제
예제 테이블
아래와 같은 내용의 예제 테이블을 생성하였습니다
create table TBNameList(
seq int not null,
name varchar(50) not null,
tel varchar(13)
)
-------------------------
insert into TBNameList values(1, '김수현', NULL)
insert into TBNameList values(1, '배수지', NULL)
insert into TBNameList values(1, '배수지', '000-4567-9874')
insert into TBNameList values(1, '홍길동', '000-1234-5678')
insert into TBNameList values(2, '김윤아', '000-5678-3456')
insert into TBNameList values(2, '임꺽정', NULL)
insert into TBNameList values(3, '박보검', '000-1234-6543')
insert into TBNameList values(4, '김동현', NULL)
insert into TBNameList values(4, '이지은', '000-0025-2054')
생성 후 조회 하면 아래와 같습니다.
select *
from TBNameList
order by Seq, name, Tel
--------------------------------
Seq Name Tel
1 김수현 NULL
1 배수지 NULL
1 배수지 000-4567-9874
1 홍길동 000-1234-5678
2 김윤아 000-5678-3456
2 임꺽정 NULL
3 박보검 000-1234-6543
4 김동현 NULL
4 이지은 000-0025-2054
위의 예제 테이블을 활용하여 Name컬럼을 구분자로 나누어 붙이도록 하는 예제를 진행합니다.
3번째 이름 뒤에 구분자는 -을 사용, 그 외 구분자는 / 를 사용합니다.
커서 예제
DECLARE @Seq int, @Name nvarchar(30), @Tel nvarchar(20)
DECLARE @String nvarchar(4000)
DECLARE @CNT int
set @CNT = 0
DECLARE CS_NameList cursor for
select *
from TBNameList
order by Seq, name, Tel
open CS_NameList
FETCH NEXT FROM CS_NameList
into @Seq, @Name, @Tel
while @@FETCH_STATUS = 0
begin
if @CNT = 0
begin
set @String = @Name
end
else if @CNT%3 = 0
begin
set @String = @String + '-' + @Name
end
else if @CNT%3 <> 0
begin
set @String = @String + '/' + @Name
end
set @CNT = @CNT +1
FETCH NEXT FROM CS_NameList
into @Seq, @Name, @Tel
end
CLOSE CS_NameList
DEALLOCATE CS_NameList
select @String as NameList
while문에 조건으로 들어가있는 @@FETCH_STATUS 는 현재 커서의 상태값을 반환합니다.
커서의 상태값을 활용하여 Loop문을 작동 시킵니다.
0 : 구문성공
1 : 구문실패 또는 반환 결과가 없음
2 : 반환 Row가 없음
while문 내부에 있는 FETCH NEXT FROM 문을 통해 커서가 다음 행을 가르키며,
해당 결과가 없을 시 while문이 종료됩니다.
Outro
이와 같이 커서를 통하여 Loop문을 동작시켜 원하는 순서로의 행단위 작업을 실행하는 방법에 대해서 알아봤습니다.
위 예제는 뭔가 조금 애매한 설명이 될 수도 있겠지만,
앞에 행을통해 다음행에 영향을 주는 작업등을 하게될때 많은 도움이 된다고 생각합니다.
한번 쯤 활용해보시는 것을 추천드리네요 :)
감사합니다.
'DATABASE > MsSQL' 카테고리의 다른 글
[MsSQL] 모든 DB에 한번 쿼리 던지기 / DB 모를 때 (SP_MSFOREACHDB 활용하기) (0) | 2024.02.13 |
---|---|
[DBA][MsSQL] Index 사용량 조회 / 미사용 Index 확인 (0) | 2024.02.10 |
[MsSQL] Database 복구 모델 - Simple, Full (단순 모델, 전체 모델) (0) | 2023.10.16 |
[MsSQL] OUTPUT - Update 사용 시, 변경 전/후 행 반환하기 (deleted/inserted) (0) | 2023.09.07 |
[MsSQL] OUTPUT - Delete 사용 시, 삭제 된 행 반환하기 (deleted) (0) | 2023.09.05 |
[MsSQL] OUTPUT - Insert 사용 시, 삽입 된 행 반환하기 (Inserted) (0) | 2023.09.04 |
[MsSQL] 자주 쓰는 쿼리 - Data File Size, Data File 경로 확인 (MDF, NDF) (1) | 2023.09.02 |
[MsSQL] Exception / Throw 사용 시 주의 사항 - rollback (1) | 2023.08.05 |