Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

달바라기

[오라클] split to row 구현 본문

프로그래밍 관련

[오라클] split to row 구현

착한악마 2018. 1. 30. 11:04

오라클에서 문자열을 split 한 후 그 결과를 로우로 리턴 받고 싶은 경우가 있을 수 있습니다.

예를 들어

 

 123▨9214▨432▨567▨8867

 

와 같은 문자열을

 

 123 
 9214
 432
 567
 8867

 

와 같은 형태로 변경해야 할 때가 있습니다.

그러나 오라클에는 split 함수가 존재하지 않고, 결과가 다중 로우로 떨어지기에 별도의 함수를 만들기도 어렵습니다.

 

이럴 때 쓸만한 방법을 만들어 보았으니 필요하신 분들께 도움이 되었으면 합니다.

 

아이디어 1

오라클 10g 부터 지원하는 regexp_substr 함수를 활용하면 쉽게 구분자 사이의 값을 가져 올 수 있습니다.

regexp_substr 참고 -> https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions138.htm#SQLRF06303

 

regexp_substr( 대상문자열, 패턴, 시작위치, 매칭순번)

select regexp_substr('123▨9214▨432▨567▨8867', '[^▨]+', 1, 3) from dual

--> 432

 

참고로 [^▨]+ 이 정규식 표현은 ▨이 아닌 문자열을 뜻합니다.

 

아이디어 2

결과 로우 수 계산

regexp_replace 참고 -> https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions137.htm#SQLRF06302

 

regexp_replace( 대상문자열, 패턴, 바꿀문자열)

select regexp_replace('123▨9214▨432▨567▨8867', '[^▨]+', '') from dual

-->▨▨▨▨

 

참고로 바꿀문자열을 생략하면 찾은문자열을 대상문자열에서 지워버립니다.

주의 할 점은 만약 대상문자열에 구분자가 없는 경우 

'123'

결과는 null이 된다는 것입니다.

select length(nvl(regexp_replace('123▨9214▨432▨567▨8867', '[^▨]+', ''), 0)) + 1
  from dual

--> 5

 

 

아이디어 3

오라클 결과에 재귀를 돌릴 수 있는 connect by 구문을 사용하면 더미 row를 만들 수 있습니다.

select '123▨9214▨432▨567▨8867' as str from dual
connect by rownum <= 3

 

-->

 123▨9214▨432▨567▨8867
 123▨9214▨432▨567▨8867
 123▨9214▨432▨567▨8867

 

 

* 결과

select regexp_substr(a.mydatas,'[^▨]+', 1, rownum) as mydata
  from (select '123▨9214▨432▨567▨8867' as mydatas from dual) a
connect by rownum <= length(regexp_replace(mydatas,'[^▨]+')) + 1

--->

 123 
 9214
 432
 567
 8867

 

위 쿼리의 제약사항은

 - split을 실행 할 대상 row가 단일행이어야 합니다. 다시 말해 from 절 서브쿼리 a의 결과가 1행이어야 합니다.

   connect by 이후 where 절이 실행 되므로  from 절 서브쿼리로 단일행의 결과를 만든 후 작업을 진행하지 않으면 대상 테이블을 full scan 합니다.

 

 

그럼 여기서 한 단계 더 나가서 다중행 결과를 split 처리 하려면?

 

!!!  다중행 split to row !!!

select a.myid
     , b.seq 
     , regexp_substr(a.mydatas,'[^▨]+', 1, b.seq) as mydata
from (select origin.myid
           , origin.mydatas
           , nvl(LENGTH(regexp_REPLACE(origin.mydatas,'[^▨]+')), 0) + 1 cnt
       from (select 'ab' as myid, '123▨921432▨567' as mydatas from dual union
             select 'er' as myid, '914' as mydatas from dual union
             select 'ff' as myid, '924▨4302' as mydatas from dual ) origin) a
     , (select rownum seq
          from dual
        CONNECT BY ROWNUM <= 100) b
 where b.seq <= a.cnt
order by a.myid, b.seq

-->

 ab   1  1  123
 ab  1  2  921432
 ab  1  3  567
 er  2  1  914
 ff  3  1  924
 ff  3  2  4302

 

 

요런 식으로 하시면 되겠습니다.

from 절의 b가 더미 테이블로 'CONNECT BY ROWNUM <= 100' 이 부분의 숫자를 조절하여 최대 결과 row 수를 조절 하시면 되겠습니다.

 

그럼 즐 코딩!!!

 

 

ps. 만약 값이 비어서 구분자가 곂쳐 있다면.. 예를 들어

'123▨9214▨▨▨432▨567▨8867'

중간에 null 값을 건너 띄고 값을 가져오는 오류가 발생합니다.

피하는 방법이 여러가지 있을 텐데 저는 쉽게 

trim(regexp_substr(replace(a.mydatas, '▨', '▨ '),'[^▨]+', 1, rownum))

요런식으로 구분자+스페이스로 바꾸고 trim 시키는 방법을 써보았습니다.