커서는 MySQL의 Stored Procedure에서 복수의 행에 어떤 쿼리들을 반복적으로 수행하고자 할 때, 사용하는 구문이다.
Java, Javascript에서 사용되는 .forEach()
또는 C언어의 포인터
와 비슷한 기능을 한다고 볼 수 있다.
MySQL에서 복수의 데이터에 쿼리를 수행하고 싶다면, 굳이 커서를 쓸 필요없이 WHERE
문에 원하는 조건을 줘서 해당 조건을 만족하는 행들에 쿼리를 수행하면 된다.
근데 왜 굳이 Cusor가 왜 필요한 것일까?
그 이유는 위에서도 이야기했듯이 .forEach
와 같은 기능이 필요한 경우가 있기 때문이다.
예를 들어서, 사용자 테이블에서 사용자들을 모두 가져와서 각 행들을 돌면서 뭔가를 수행하고 싶은 경우에 Cusor를 사용할 수 있다.
이렇게 어떤 조건을 만족하는 데이터를 SELECT
문으로 가져와서, 그 결과들에 대해서 반복문이 돌고 싶다면, Cursor를 사용하는 게 좋은 접근이 될 수 있다.
Cusor는 일반적인 프로그래밍 언어와 비교했을 때, 조금 복잡한 사용법을 갖고 있고 아래와 같이 사용해야한다.
DECLARE
: SELECT한 결과를 Cursor로 선언DECLARE HANDLER
: 반복 조건 선언OPEN
: 커서 열기FETCH
: 커서에서 현재 행 가져오기CLOSE
: 커서 닫기자! 그럼 이제 좀 더 실제적인 예시로 Cusor를 다뤄보자 🔥
1. 모든 사용자를 조회한다.
2. 각 사용자의 이름과 나이를 합친 문자열을 로그 테이블에 기록한다.
우리가 만들 기능을 이렇게 설정해보도록 하겠다.
INSERT INTO
`user` (`name`, `age`)
VALUES
("Lebron", 20),
("Messi", 21),
("Ronaldo", 22),
("Xavi", 23),
("Harry", 24),
("Rooney", 25);
먼저 위와 같이 user
테이블을 만들고, 샘플 데이터를 만들어주자.
그리고 이렇게 유저에 대한 로그를 기록할 수 있는 user_log
테이블도 만들어주자.
CREATE DEFINER=`root`@`localhost` PROCEDURE `userLogger`()
BEGIN
DECLARE _userId BIGINT;
DECLARE _userName VARCHAR(255);
DECLARE _userAge INT;
DECLARE done BOOLEAN DEFAULT FALSE;
DECLARE user_cursor CURSOR FOR SELECT * FROM `user`;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN user_cursor;
sample_loop:LOOP
IF done THEN
LEAVE sample_loop;
END IF;
FETCH user_cursor INTO _userId, _userName, _userAge;
SET @content = CONCAT(_userName, _userAge);
INSERT INTO `user_log` (`content`, `user_id`) VALUES(@content, _userId);
END LOOP;
CLOSE user_cursor;
END
우리가 필요한 기능을 이렇게 userLogger
라는 이름으로 만들어보았다. 아무 설명이 없으면 이해하기 힘드니까, 주석을 추가하고 프로시져의 실행부만 가져와보겠다. 😊
BEGIN
##########
# 선언부
##########
DECLARE _userId BIGINT; # user의 id를 담을 변수
DECLARE _userName VARCHAR(255); # user의 이름을 담을 변수
DECLARE _userAge INT; # user의 나이를 담을 변수
DECLARE done BOOLEAN DEFAULT FALSE; # 커서 종료 상태를 담을 변수
DECLARE user_cursor CURSOR FOR SELECT * FROM `user`; # 커서
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE; # 커서 종료 조건
##########
# 커서 열기
##########
OPEN user_cursor;
##########
# 반복문
##########
sample_loop:LOOP
# 반복문 종료 쿼리
IF done THEN
LEAVE sample_loop;
END IF;
# 커서 FETCH
FETCH user_cursor INTO _userId, _userName, _userAge;
# FETCHING한 데이터를 갖고 필요한 쿼리 수행
SET @content = CONCAT(_userName, _userAge);
INSERT INTO `user_log` (`content`, `user_id`) VALUES(@content, _userId);
END LOOP;
##########
# 커서 닫기
##########
CLOSE user_cursor;
END
짜잔~
이전 섹션들에서 설명한대로 변수 선언, 커서 선언등등의 정해진 순서대로 Stored Procedure를 작성한 모습이다.
이 SP를 실행하면 어떻게 될까? 바~로 실행해보겠다.
CALL userLogger();
위와 같이 userLogger
SP를 호출하면 아래와 같은 결과를 얻을 수 있다.
사실 요즘 대부분의 DB관련 로직은 ORM이나 쿼리 빌더를 통해서 간편하게 처리해서, Cusor를 쓸 일이 거의 없을 가능성이 높다 ㅎㅎ
하지만, Stored Procedure를 쓰면서 조회한 데이터들에 대해서 반복문을 돌고 싶은 경우가 생긴다면 Cusor를 사용해서 깔끔하게 처리해보는 것도 좋을 것이다.
그럼 이번 글은 마치도록 하겠다 🔥
글 잘 봤습니다.