DB

[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

 

Leave a Reply

error: Content is protected !!