[MSSQL]프로시저 내에서 CURSOR 대신 WHILE 사용하여 반복처리하는 방법
프로시저 내에서 여러가지 작업을 반복적으로 처리해야할 때 CURSOR를 사용해도 되지만 WHILE문을 사용하여 FOREACH문과 동일한 효과를 볼 수 있다.
프로시저내에서 WHILE문을 사용하여 WHILE문 안에서 여러 작업을 처리해야할 경우,
조회한 결과 리스트에 RONUM 칼럼을 생성 후 ROWNUM의 조건에 WHILE문의 조건문을 추가하여 처리하는 경우
여러개의 데이터가 있을 때(ROW별 데이터는 다른 경우) 조회결과가 가장 마지막값으로 처리되는 문제가 생긴다.
그럼으로 이럴 때는 반드시 테이블 변수를 선언하거나 임시테이블을 생성 후 조회결과를 먼저 INSERT 처리 후
WHILE문에서 임시테이블이나 테이블 변수를 반복처리해야한다.
그래야 WHILE문의 오류(?)를 범할 수 있다.
그 샘플 스크립트는 다음과 같다.
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[SP_TEST_WHILE_S]
AS
SET NOCOUNT ON
DECLARE @V_EMP_ID VARCHAR(30) ='' --USER_ID
DECLARE @V_DESC VARCHAR(1000) = '' --비고(내용)
DECLARE @V_PHONE VARCHAR(30) = '' --휴대전화번호
DECLARE @V_USER_ID VARCHAR(30) = 'admin'
DECLARE @V_STATUS VARCHAR(30) = '' --처리 상태명
DECLARE @V_CRT_TIME VARCHAR(30) = '' --작성일자
DECLARE @P_ERROR_CD VARCHAR(30) = ''
DECLARE @P_RETURN_STR NVARCHAR(100) = ''
DECLARE @V_TODAY VARCHAR(10) = CONVERT(VARCHAR(10),GETDATE(), 120) --2022-02-22
BEGIN
BEGIN TRY
DECLARE @P_INDEX INT = 1
DECLARE @P_MAX INT = 0
--TEST
--SET @V_TODAY = '2021-12-22'
--0. 등록 대상 개수 파악
SELECT @P_MAX = COUNT(1)
FROM TB_TEST a
WHERE a.CreateDateDatetime BETWEEN CONVERT(datetime, @V_TODAY) AND CONVERT(datetime, @V_TODAY + ' 23:59:59')
AND a.CreateDateDatetime NOT IN (SELECT KEY FROM TB_INST_HIST ) --이미 등록한 건 제외처리
IF @P_MAX > 0
BEGIN
--1. 반드시 임시테이블 변수에 INSERT 후 처리해야 WHILE의 오류를 피할 수 있다.
DECLARE @TResults TABLE (
ROWNUM INT
,V_DESC VARCHAR(1000)
,V_DEPT_NM VARCHAR(30)
,V_EMP_NM VARCHAR(30)
,V_CRT_TIME VARCHAR(30)
,V_PHONE VARCHAR(30)
,V_STATUS VARCHAR(30)
)
INSERT @TResults (
ROWNUM, V_DESC, V_EMP_NM, V_CRT_TIME, V_PHONE, V_STATUS)
SELECT
ROW_NUMBER() OVER (ORDER BY a.idx ASC, a.gubun ASC) ROWNUM
,a.UserIdx
,a.[desc]
,a.AgencyName
,a.CreateDateDatetime
,a.PhoneNum
,CASE WHEN a.gubun ='테스트' THEN '90'
WHEN a.gubun ='리얼' THEN '100' ELSE '' END
,a.StatusName
FROM TB_TEST a
WHERE a.CreateDateDatetime BETWEEN CONVERT(datetime, @V_TODAY) AND CONVERT(datetime, @V_TODAY + ' 23:59:59')
AND a.CreateDateDatetime NOT IN (SELECT KEY FROM TB_INST_HIST ) --이미 등록한 건 제외처리
--2. 등록 대상 개수 만큼 반복 처리
WHILE @P_INDEX <= @P_MAX
BEGIN
-- 2-1. 저장할 데이터 변수에 담기
SELECT
@V_DESC = V_DESC
,@V_EMP_NM = V_EMP_NM
,@V_CRT_TIME = V_CRT_TIME
,@V_PHONE = V_PHONE
,@V_STATUS = V_STATUS
FROM @TResults
WHERE ROWNUM = @P_INDEX
--처리대상 데이터 확인 쿼리
SELECT
@V_DESC AS V_DESC
, @V_EMP_NM AS V_EMP_NM
, @V_CRT_TIME AS V_CRT_TIME
, @V_PHONE AS V_PHONE
, @V_STATUS AS V_STATUS
,@P_INDEX AS P_INDEX
--특정 데이터 조회해서 변수값으로 설정
SELECT TOP 1
@V_EMP_ID = ce.USER_ID
FROM ..............
--2-3. INSERT 작업
INSERT INTO .......
--2-4. INSERT 작업
INSERT INTO .......
--2-5. INSERT 작업
INSERT INTO .....
--2-7. INSERT 작업
INSERT INTO .....
SET @P_INDEX = @P_INDEX + 1;
END
END
END TRY
BEGIN CATCH
DECLARE @V_EXEC_INFO NVARCHAR(MAX);
-- 실행 조건
SELECT @V_EXEC_INFO = N'SP_TEST_WHILE_S'
-- SP에러로그 기록
INSERT SP_ROC_ERR_LOG (ERR_PROC, ERR_CD, ERR_STA, ERR_MSG, EXEC_PROC_INFO)
SELECT
ERR_PROC = ERROR_PROCEDURE(),
ERR_CD = CONVERT(VARCHAR(100), ERROR_NUMBER()),
ERR_STA = CONVERT(VARCHAR(100), ERROR_SEVERITY()) + '|' + CONVERT(VARCHAR(100), ERROR_STATE()) + '|' + CONVERT(VARCHAR(100), ERROR_LINE()),
ERR_MSG = ERROR_MESSAGE(),
EXEC_PROC_INFO = @V_EXEC_INFO
;
END CATCH;
END