728x90
CTE 를 쓰는 경우 아래와 같이 해결할 수 있겠지만
국내 검색 결과에는 모두 CTE의 경우에 대한 답변 뿐이라 영문 검색을 할 수 밖에 없었다.
"procedure, function, trigger, or view nesting level exceeded (limit 32)"
결론은 프로시저나 트리거 뷰에서는 재귀최대횟수를 어찌할 수 없다.
;WITH CTE ...
SELECT *
FROM TABLE
OPTION (MAXRECURSION 0) -- 이 옵션을 주면 무한루프로 돌수있고 원하는 레벨이 있으면 줘도 된다.
저장 프로시저, 함수, 트리거 또는 뷰의 최대 중첩 수준은 32레벨을 넘을 수 없게 지정되어 있다.
어쩔 수 없이 해당 중첩을 분기하거나 32 이상은 포기해야 한다.
아래와 같이 RECURSIVE를 호출하는 부분에서 LEVEL에 대한 값을 인자로 전달하고 제어하면,
오류를 막을 수 있다.
재귀로 수행하는 SP 명은 [PROC_FIND_SOURCE_LINK] 이고
@R_CNT 변수를 입력파라메터로 전달했다.
재귀 호출 전에 해당 값을 증가 시켜 다음 레벨 호출 시 전달하고
SP 내부에서는 @R_CNT를 체크해서 32회가 넘지 않도록 처리한다.
참고로 아래는 BOTTOM_UP 으로 트리를 순회하는 과정중에 사용한 SP이다.
ALTER PROC [dbo].[PROC_FIND_SOURCE_LINK](
@START_LINK INT
,@MAP_ID INT
,@R_CNT INT = 1
)
AS
BEGIN
DECLARE @TMP_WORK_DATE datetime2(4)
DECLARE @FIND_LINK INT
DECLARE @FIND_LINK_ST INT
DECLARE @FIND_LINK_ED INT
DECLARE @LINK2 INT
DECLARE @LINK2_ST INT
DECLARE @LINK2_ED INT
DECLARE @LINK3 INT
DECLARE @LINK3_ST INT
DECLARE @LINK3_ED INT
--print('[PROC_FIND_SOURCE_LINK] ' + convert(varchar(100),@START_LINK)+':'+convert(varchar(100),@MAP_ID))
WHILE (@R_CNT < 31)
BEGIN
IF EXISTS ( SELECT * FROM TMP_HRTM_LINK_SHAPE WHERE TYPE = 1 AND (LINK_ID_2 = @START_LINK OR LINK_ID_3 = @START_LINK) )
BEGIN
SELECT @TMP_WORK_DATE = WORK_DATE, @FIND_LINK = LINK_ID_1, @LINK2 = LINK_ID_2, @LINK3=LINK_ID_3 FROM TMP_HRTM_LINK_SHAPE WHERE TYPE = 1 AND (LINK_ID_2 = @START_LINK OR LINK_ID_3 = @START_LINK)
INSERT INTO TMP_HUID(HUID, USE_YN, WORK_DATE)
SELECT UID,USE_YN,INSERT_DATE
FROM RTM_LINK_UID
WHERE ORI_MAP_ID = @MAP_ID AND ORI_ID = @FIND_LINK
--print(':1 '+convert(varchar(100),@R_CNT))
SET @R_CNT = @R_CNT+1
EXEC PROC_FIND_SOURCE_LINK @FIND_LINK,@MAP_ID,@R_CNT
/*정역 검증 데이터 추가*/
;WITH SORCE
AS ( SELECT WORK_DATE,LINK_MAP_ID,LINK_ID,ST_ND_ID,ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @FIND_LINK AND LINK_MAP_ID = @MAP_ID AND OP_CODE = 'R')
,TAR1
AS (SELECT WORK_DATE,LINK_MAP_ID,LINK_ID,ST_ND_ID,ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @LINK2 AND LINK_MAP_ID = @MAP_ID AND OP_CODE = 'I')
,TAR2
AS (SELECT WORK_DATE,LINK_MAP_ID,LINK_ID,ST_ND_ID,ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @LINK3 AND LINK_MAP_ID = @MAP_ID AND OP_CODE = 'I')
INSERT INTO COPY_HRTM_LINK_REVERSE(WORK_DATE,LINK_MAP_ID,SRC_LINK_ID,SRC_ST_ND,SRC_ED_ND,TAR_LINK_ID,TAR_ST_ND,TAR_ED_ND,TYPE,REVERSE)
SELECT *
FROM (SELECT DISTINCT A.WORK_DATE,A.LINK_MAP_ID,A.LINK_ID,A.ST_ND_ID,A.ED_ND_ID,B.LINK_ID AS T_LINK_ID,B.ST_ND_ID AS T_ST_ND_ID,B.ED_ND_ID AS T_ED_ND_ID,1 AS T ,CASE WHEN @LINK2 > @LINK3 THEN 1 ELSE 0 END AS C
FROM SORCE A JOIN TAR1 B ON A.WORK_DATE = B.WORK_DATE AND A.LINK_MAP_ID = B.LINK_MAP_ID
UNION
SELECT DISTINCT A.WORK_DATE,A.LINK_MAP_ID,A.LINK_ID,A.ST_ND_ID,A.ED_ND_ID,B.LINK_ID AS T_LINK_ID,B.ST_ND_ID AS T_ST_ND_ID,B.ED_ND_ID AS T_ED_ND_ID,1 AS T,CASE WHEN @LINK2 > @LINK3 THEN 0 ELSE 1 END AS C
FROM SORCE A JOIN TAR2 B ON A.WORK_DATE = B.WORK_DATE AND A.LINK_MAP_ID = B.LINK_MAP_ID ) A
OPTION ( MAXRECURSION 0 )
BREAK;
END
ELSE IF EXISTS ( SELECT * FROM TMP_HRTM_LINK_SHAPE WHERE TYPE = 2 AND LINK_ID_3 = @START_LINK )
BEGIN
--print(':2-1 '+convert(varchar(100),@R_CNT))
SET @R_CNT = @R_CNT+1
--한쪽 링크 따라가기
SELECT @FIND_LINK = LINK_ID_1, @LINK2 = LINK_ID_2, @LINK3=LINK_ID_3 FROM TMP_HRTM_LINK_SHAPE WHERE TYPE = 2 AND LINK_ID_3 = @START_LINK
INSERT INTO TMP_HUID(HUID, USE_YN, WORK_DATE)
SELECT UID,USE_YN,INSERT_DATE
FROM RTM_LINK_UID
WHERE ORI_MAP_ID = @MAP_ID AND ORI_ID = @FIND_LINK
EXEC PROC_FIND_SOURCE_LINK @FIND_LINK,@MAP_ID,@R_CNT
--반대쪽 링크 따라가기
--print(':2-2 '+convert(varchar(100),@R_CNT))
SELECT @FIND_LINK = LINK_ID_2, @LINK2 = LINK_ID_1, @LINK3=LINK_ID_3 FROM TMP_HRTM_LINK_SHAPE WHERE TYPE = 2 AND LINK_ID_3 = @START_LINK
INSERT INTO TMP_HUID(HUID, USE_YN, WORK_DATE)
SELECT UID,USE_YN,INSERT_DATE
FROM RTM_LINK_UID
WHERE ORI_MAP_ID = @MAP_ID AND ORI_ID = @FIND_LINK
EXEC PROC_FIND_SOURCE_LINK @FIND_LINK,@MAP_ID,@R_CNT
/*정역 검증 데이터 추가*/
SELECT @TMP_WORK_DATE = WORK_DATE, @LINK3 = LINK_ID_2, @LINK2 = LINK_ID_1, @FIND_LINK=LINK_ID_3 FROM TMP_HRTM_LINK_SHAPE WHERE TYPE = 2 AND LINK_ID_3 = @START_LINK
-- 병합 전 링크 정보 @FIND_LINK
SELECT @FIND_LINK_ST = ST_ND_ID, @FIND_LINK_ED = ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @FIND_LINK AND LINK_MAP_ID = @MAP_ID AND OP_CODE = 'I'
-- 분할 후 링크 정보
IF (SELECT COUNT(*) FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @LINK2 AND LINK_MAP_ID = @MAP_ID) = 2
BEGIN
SELECT @LINK2_ST = ST_ND_ID, @LINK2_ED = ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @LINK2 AND LINK_MAP_ID = @MAP_ID AND OP_CODE IN('U')
SELECT @LINK3_ST = ST_ND_ID, @LINK3_ED = ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @LINK3 AND LINK_MAP_ID = @MAP_ID AND OP_CODE IN('R')
END
ELSE
BEGIN
SELECT @LINK2_ST = ST_ND_ID, @LINK2_ED = ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @LINK2 AND LINK_MAP_ID = @MAP_ID AND OP_CODE IN('R')
SELECT @LINK3_ST = ST_ND_ID, @LINK3_ED = ED_ND_ID FROM COPY_HRTM_LINK_CURE WHERE WORK_DATE = @TMP_WORK_DATE AND LINK_ID = @LINK3 AND LINK_MAP_ID = @MAP_ID AND OP_CODE IN('U')
END
IF @LINK2_ST = @LINK3_ST --SOURCE ST/ND 중 ST 가 같으면 ED 가 다른것 기준으로 REVERSE
BEGIN
INSERT INTO COPY_HRTM_LINK_REVERSE(WORK_DATE,LINK_MAP_ID,SRC_LINK_ID,SRC_ST_ND,SRC_ED_ND,TAR_LINK_ID,TAR_ST_ND,TAR_ED_ND,TYPE,REVERSE)
SELECT @TMP_WORK_DATE,@MAP_ID,@LINK2,@LINK2_ST,@LINK2_ED,@FIND_LINK,@FIND_LINK_ST,@FIND_LINK_ED,2,CASE WHEN @LINK2_ED <> @FIND_LINK_ED THEN 1 ELSE 0 END
INSERT INTO COPY_HRTM_LINK_REVERSE(WORK_DATE,LINK_MAP_ID,SRC_LINK_ID,SRC_ST_ND,SRC_ED_ND,TAR_LINK_ID,TAR_ST_ND,TAR_ED_ND,TYPE,REVERSE)
SELECT @TMP_WORK_DATE,@MAP_ID,@LINK3,@LINK3_ST,@LINK3_ED,@FIND_LINK,@FIND_LINK_ST,@FIND_LINK_ED,2,CASE WHEN @LINK3_ED <> @FIND_LINK_ED THEN 1 ELSE 0 END
END
ELSE IF @LINK2_ED = @LINK3_ED --SOURCE ST/ND 중 ND 가 같으면 ST 가 다른것 기준으로 REVERSE
BEGIN
INSERT INTO COPY_HRTM_LINK_REVERSE(WORK_DATE,LINK_MAP_ID,SRC_LINK_ID,SRC_ST_ND,SRC_ED_ND,TAR_LINK_ID,TAR_ST_ND,TAR_ED_ND,TYPE,REVERSE)
SELECT @TMP_WORK_DATE,@MAP_ID,@LINK2,@LINK2_ST,@LINK2_ED,@FIND_LINK,@FIND_LINK_ST,@FIND_LINK_ED,2,CASE WHEN @LINK2_ST <> @FIND_LINK_ST THEN 1 ELSE 0 END
INSERT INTO COPY_HRTM_LINK_REVERSE(WORK_DATE,LINK_MAP_ID,SRC_LINK_ID,SRC_ST_ND,SRC_ED_ND,TAR_LINK_ID,TAR_ST_ND,TAR_ED_ND,TYPE,REVERSE)
SELECT @TMP_WORK_DATE,@MAP_ID,@LINK3,@LINK3_ST,@LINK3_ED,@FIND_LINK,@FIND_LINK_ST,@FIND_LINK_ED,2,CASE WHEN @LINK3_ST <> @FIND_LINK_ST THEN 1 ELSE 0 END
END
ELSE
BEGIN
INSERT INTO COPY_HRTM_LINK_REVERSE(WORK_DATE,LINK_MAP_ID,SRC_LINK_ID,SRC_ST_ND,SRC_ED_ND,TAR_LINK_ID,TAR_ST_ND,TAR_ED_ND,TYPE,REVERSE)
SELECT @TMP_WORK_DATE,@MAP_ID,@LINK2,@LINK2_ST,@LINK2_ED,@FIND_LINK,@FIND_LINK_ST,@FIND_LINK_ED,2,0
INSERT INTO COPY_HRTM_LINK_REVERSE(WORK_DATE,LINK_MAP_ID,SRC_LINK_ID,SRC_ST_ND,SRC_ED_ND,TAR_LINK_ID,TAR_ST_ND,TAR_ED_ND,TYPE,REVERSE)
SELECT @TMP_WORK_DATE,@MAP_ID,@LINK3,@LINK3_ST,@LINK3_ED,@FIND_LINK,@FIND_LINK_ST,@FIND_LINK_ED,2,0
END
BREAK;
END
ELSE
BREAK;
--PRINT (CONVERT(VARCHAR(100),@R_CNT))
END
END
관련 자료 : https://www.sqlservercurry.com/2015/03/sql-server-stored-procedure-recursion.html
'프로그래밍 > TSQL' 카테고리의 다른 글
[MSSQL] BCP 취소하기 (0) | 2020.06.29 |
---|---|
[MSSQL] 인스턴스 확인, DB명 확인, 서버 확인 (0) | 2020.04.28 |
[MSSQL] 문자열 비교하기 ( 동일한 부분만 리턴하기 ) (0) | 2020.04.14 |
[MSSQL] MDF, LDF 이동 / DB 상위 버전->하위 버전으로 이동 시 오류 발생 (0) | 2020.02.21 |
조인 조건절 위치에 따른 차이 설명 (SQL join where clause vs on clause) (0) | 2020.02.14 |
댓글