728x90
두개의 문자열을 비교해서 동일한 부분만 출력하고 싶을 때 아래 방식으로 함수를 구현할 수 있습니다.
아래 예시는 동일한 문자열에 경우에 한해서 작성되었고,
목적은 아래와 같이 문자열이 입력되었을 때 '/' 문자열 기준으로 동일하게 분리된 문자열만 살리는 일종의
XOR 연산과 같은 동작을 구현하는데 있습니다.
문자열 1 : 가/나다/라/마/바사
문자열 2 : 가나다/라마/바사
결과 : 가나다/라마/바사
사용 기술 : CTE, 재귀, STUFF
MSSQL, TSQL 로 문자열 만지기, 재귀(RECURSIVE) 구현하기 재밋네요
code 공유 드립니다.
DECLARE @RESULT VARCHAR(100), @STR1 VARCHAR(100),@STR2 VARCHAR(100)
DECLARE @SEP VARCHAR(2)
DECLARE @MAX INT
SET @STR1 = '가나다/라바사'
SET @STR2 = '가나다/라/바사'
--SET @STR1 = '트와이스/짱'
--SET @STR2 = '트/와/이스짱'
SET @SEP= '/'
SET @MAX = CASE WHEN LEN(@STR1) > LEN(@STR2) THEN LEN(@STR1) ELSE LEN(@STR2) END
--1차 가공한자씩 봐서 '/'앞뒤 지우기
IF @SEP = LEFT(@STR1,1)
SET @STR1 = RIGHT(@STR1,LEN(@STR1)-1)
IF @SEP = RIGHT(@STR1,1)
SET @STR1 = LEFT(@STR1,LEN(@STR1)-1)
IF @SEP = LEFT(@STR2,1)
SET @STR2 = RIGHT(@STR2,LEN(@STR2)-1)
IF @SEP = RIGHT(@STR2,1)
SET @STR2 = LEFT(@STR2,LEN(@STR2)-1)
IF REPLACE(@STR1,@SEP,'') = REPLACE(@STR1,@SEP,'')
BEGIN
;WITH EACH(A_NAME,B_NAME,OFFSET_A,A_KEY,OFFSET_B,B_KEY)
AS (
--ANCHOR
SELECT @STR1,@STR2
,1 AS OFFSET_A,SUBSTRING(@STR1,1,1) AS KEY_A
,1 AS OFFSET_B,SUBSTRING(@STR2,1,1) AS KEY_B
UNION ALL
--RECURSIVE
SELECT @STR1,@STR2
, CASE WHEN SUBSTRING(@STR1,OFFSET_A+1,1) = SUBSTRING(@STR2,OFFSET_B+1,1)
THEN OFFSET_A+1
ELSE
CASE WHEN SUBSTRING(@STR2,OFFSET_B+1,1) = @SEP
THEN OFFSET_A
ELSE OFFSET_A+1
END
END AS OFFSET_A
, SUBSTRING(@STR1, CASE WHEN SUBSTRING(@STR1,OFFSET_A+1,1) = SUBSTRING(@STR2,OFFSET_B+1,1)
THEN OFFSET_A+1
ELSE
CASE WHEN SUBSTRING(@STR2,OFFSET_B+1,1) = @SEP
THEN OFFSET_A
ELSE OFFSET_A+1
END
END,1)
, CASE WHEN SUBSTRING(@STR1,OFFSET_A+1,1) = SUBSTRING(@STR2,OFFSET_B+1,1)
THEN OFFSET_B+1
ELSE
CASE WHEN SUBSTRING(@STR1,OFFSET_A+1,1) = @SEP
THEN OFFSET_B
ELSE OFFSET_B+1
END
END AS OFFSET_B
, SUBSTRING(@STR2, CASE WHEN SUBSTRING(@STR1,OFFSET_A+1,1) = SUBSTRING(@STR2,OFFSET_B+1,1)
THEN OFFSET_B+1
ELSE
CASE WHEN SUBSTRING(@STR1,OFFSET_A+1,1) = @SEP
THEN OFFSET_B
ELSE OFFSET_B+1
END
END,1)
FROM EACH AA
WHERE OFFSET_A < @MAX AND OFFSET_B < @MAX
--EXIT CONDITION
)
-- SAME CHARCTER ONLY
,RESULT
AS
(
SELECT *
FROM EACH
WHERE A_KEY = B_KEY
)
-- RESULT SET
SELECT @RESULT = KEYS
FROM ( SELECT DISTINCT REPLACE(STUFF((SELECT '$'+A_KEY
FROM RESULT FOR XML PATH('')),1,1,''),'$','') AS KEYS
FROM RESULT ) A
END
ELSE
SET @RESULT = NULL
SELECT @RESULT
구현 방식
- 1 입력 문자열에 대한 유효성 체크 : 입력 문자열의 오류 상황을 제어한다.
--1차 가공한자씩 봐서 '/'앞뒤 지우기
IF @SEP = LEFT(@STR1,1)
SET @STR1 = RIGHT(@STR1,LEN(@STR1)-1)
IF @SEP = RIGHT(@STR1,1)
SET @STR1 = LEFT(@STR1,LEN(@STR1)-1)
IF @SEP = LEFT(@STR2,1)
SET @STR2 = RIGHT(@STR2,LEN(@STR2)-1)
IF @SEP = RIGHT(@STR2,1)
SET @STR2 = LEFT(@STR2,LEN(@STR2)-1)
- 2 문자열을 각각 한단어씩 분류하기 : CTE 재귀를 이용하여 각 단어를 순회하여 성능을 확보한다.
;WITH EACH(A_NAME,B_NAME,OFFSET_A,A_KEY,OFFSET_B,B_KEY)
AS (
--ANCHOR
SELECT ...
UNION ALL
--RECURSIVE
SELECT ...
- 3 문자열 중 긴문자 기준으로 재귀 종료조건 설정 : 재귀의 종료는 둘중 긴문자열의 길이
SET @MAX = CASE WHEN LEN(@STR1) > LEN(@STR2) THEN LEN(@STR1) ELSE LEN(@STR2) END
.
.
.
WHERE OFFSET_A < @MAX AND OFFSET_B < @MAX
- 4 재귀 수행하면서 각 문자열을 비교하고 분리조건 '@SEP'에 해당하는 문자열에 dummy 삽입
--문자열 1 기준으로 설명
SUBSTRING(@STR1, CASE WHEN SUBSTRING(@STR1,OFFSET_A+1,1) = SUBSTRING(@STR2,OFFSET_B+1,1)
THEN OFFSET_A+1
ELSE
CASE WHEN SUBSTRING(@STR2,OFFSET_B+1,1) = @SEP
THEN OFFSET_A
ELSE OFFSET_A+1
END
END,1)
--해당 문자열이 잘릴위치에서 반대편 문자열이 @SEP에 해당한다면
--현재 문자는 동일한 오프셋을 유지하여 dummy값(이전문자)를 유지한다.
--각 문자에 @SEP의 위치와 개수가 다름으로 인한 처리이며
--최종 결과물 출력 시 동일한 위치의 문자만 출력되도록 처리하므로 해당 문자는 제거된다.
- 5 양쪽이 모두 일치하는 결과 조회 : 생성된 결과(DUMMY포함)를 정리하여 출력한다.
,RESULT
AS
(
SELECT *
FROM EACH
WHERE A_KEY = B_KEY
)
- 6 레코드 단위 문자열을 행으로 변경 : FOR XML과 STUFF 를 활용하여 문자열을 이어 붙이고 연결문자는 제거한다.
SELECT @RESULT = KEYS
FROM ( SELECT DISTINCT REPLACE(STUFF((SELECT '$'+A_KEY
FROM RESULT FOR XML PATH('')),1,1,''),'$','') AS KEYS
FROM RESULT ) A
'프로그래밍 > TSQL' 카테고리의 다른 글
[MSSQL] 인스턴스 확인, DB명 확인, 서버 확인 (0) | 2020.04.28 |
---|---|
[MSSQL] 저장 프로시저, 함수, 트리거 또는 뷰의 최대 중첩 수준(32) 처리 방법 (0) | 2020.04.16 |
[MSSQL] MDF, LDF 이동 / DB 상위 버전->하위 버전으로 이동 시 오류 발생 (0) | 2020.02.21 |
조인 조건절 위치에 따른 차이 설명 (SQL join where clause vs on clause) (0) | 2020.02.14 |
MSSQL 범위 지정하여 가져오기 (0) | 2020.02.07 |
댓글