문자형 날짜를 YYYYMMDD로 변환 문의 드립니다. 0 8 222

by 오뚝이 [Oracle 기초] [2019.03.12 12:51:05]


문자형으로 된 날짜를 YYYYMMDD 형태로 변환하는 함수를 만들고 있습니다.

2019년 -> NULL

2019년 01월,   2019년 1월,   2019년 1월 1일-> 20190101

 

SELECT GET_DATE_TO_YMD('2019')                                -- 결과값 : NULL          -- 정상입니다.
     , GET_DATE_TO_YMD('201903')                                -- 결과값 : 20190301    -- 정상
     , GET_DATE_TO_YMD('2019년03월')                            -- 결과값 : 20190301  -- 정상
     , GET_DATE_TO_YMD('2019년 03월')                           -- 결과값 : 20190301  -- 정상
     , GET_DATE_TO_YMD('2019년 3월')                            -- 결과값 : 20190301  -- 정상
     , GET_DATE_TO_YMD('2019년 3월 15일')                       -- 결과값 : 20190315 나와야 하는데.. NULL 입니다. ^^
  FROM DUAL;

 

정규식을 사용해야 할것 같은데..  방법은 모르겠고..

아래처럼 구현하다보니..

CASE만 늘어나서.. 정규식으로 심플하게 하는 방법이 있을것 같아..

도움 요청드립니다..

감사합니다.

 

 

CREATE OR REPLACE FUNCTION IDLOOK.GET_DATE_TO_YMD
(
    in_STR_DATE          IN VARCHAR2                                             -- 날짜(문자형)
)
/*******************************************************************************
 * 프로그램ID : GET_DATE_STR
 * 프로그램명 : 문자열 날짜를 YYYYMMDD 형태로 변환
 * 샘플       : SELECT GET_DATE_TO_YMD('2019')                                -- 결과값 : NULL
                     , GET_DATE_TO_YMD('201903')                                -- 결과값 : 20190301
                     , GET_DATE_TO_YMD('2019년03월')                            -- 결과값 : 20190301
                     , GET_DATE_TO_YMD('2019년 03월')                           -- 결과값 : 20190301
                     , GET_DATE_TO_YMD('2019년 3월')                            -- 결과값 : 20190301
                     , GET_DATE_TO_YMD('2019년 3월 15일')                       -- 결과값 : 20190315
                  FROM DUAL;
 *******************************************************************************
 * 생성자     : 2019-03-12 XXXX
 ******************************************************************************/
RETURN VARCHAR2
IS
    out_STR_DT  VARCHAR2(50) := '';

    v_TMP       VARCHAR2(50);

BEGIN

    BEGIN

        IF in_STR_DATE IS NOT NULL THEN

            v_TMP := REGEXP_REPLACE(in_STR_DATE, '[^0-9]');                     -- 숫자만 추출

            IF LENGTH(v_TMP) > 8 OR LENGTH(v_TMP) < 5 THEN

    --            out_STR_DT  := in_STR_DATE;
                out_STR_DT  := '';

            ELSIF LENGTH(v_TMP) = 5 THEN

                IF TO_NUMBER(SUBSTR(v_TMP, 1, 4)) >= 1900 AND TO_NUMBER(SUBSTR(v_TMP, 5, 1)) BETWEEN 1 AND 9 THEN

                    v_TMP  := SUBSTR(v_TMP, 1, 4) || '0' || SUBSTR(v_TMP, 5, 1);

                    out_STR_DT  := TO_CHAR(TO_DATE(RPAD(v_TMP, 8, '01')), 'YYYYMMDD');

                ELSE
                    out_STR_DT  := '';

                END IF;

            ELSE

                out_STR_DT  := TO_CHAR(TO_DATE(RPAD(v_TMP, 8, '01')), 'YYYYMMDD');

            END IF;

        END IF;

    EXCEPTION
        WHEN OTHERS THEN
            out_STR_DT := '';
    END;

    RETURN out_STR_DT;

END GET_DATE_TO_YMD;
/

 

by 마농 [2019.03.12 13:28:53]

위 케이스 외에도 다른 케이스가 더 있을 것 같은 느낌이 드네요.
가능한 케이스가 모두 나열되었으면 좋겠네요.


by 오뚝이 [2019.03.12 13:46:11]

답변 감사합니다.
현재까지 확인된 보완할 CASE는
월, 일이 각각 1자리씩 있는 경우 입니다.
EX) 2019년1월 -> 정상
     2019년1월1일 -> 오류 20191101
     2019년01월1일 -> 오류 20190110
     2019년5월1일 -> NULL
     2019년1월5일 -> NULL
     2019년3월5일 -> NULL

현행 데이터로 I/F를 진행해야하는데..
데이터 유형이 TEXT 형태로 존재하여 어려움이 있네요..

살짝 넉두리 부려봅니다. ㅎㅎ
좋은 하루되세요..

    


by 마농 [2019.03.12 13:51:14]

제가 말하는 케이스는 함수의 결과가 오류인 케이스를 말하는게 아니라
날짜 포멧의 입력 포멧에 대한 케이스를 말하는 것입니다.
이 케이스를 알아야 케이스별 적용 방법을 구상할 수 있습니다.
한글로 년월일 식으로만 입력되나요?
숫자만 온다거나 한글 대신 다른 기호(- / . 등)를 사용한다거나?


by 오뚝이 [2019.03.12 14:08:14]

입력 DATA는 TEXT 형태로.. 아래와 같습니다. ^^
일자 구분자 : 년월일, 특수(-/.) 입니다. (SPACE 포함)

2018.02
2018.02.13
2018-02
2018-02-13
2018/12
2018/12/01
2019년 1월
2019년 1월 1일
2019년 01월 01일

 


by 마농 [2019.03.12 15:03:35]

최초 질문과 좀 다른데요?
구분자 없이 년도만 온다거나? 년월만 오는 경우는 없는지? 2019, 201903, 20193
혹시 년도가 2자리만 들어오는 경우는 없는지? 19년3월3일


by 오뚝이 [2019.03.12 15:52:39]

확자성을 고려해 숫자로만 구성된 데이터도 처리 합니다.
년도가 2자리인 경우는 운영 데이터에는 없는데.. 입력 할 수는 있습니다.. ㅜㅜ
* 년도(RR, YYYY)만 존재하는 데이터는 NULL 처리합니다.
ex) 201811 같이 6자리 숫자로만 구성된 경우 YYYYMM(년월)로 처리할려고 합니다.
     201813 인 경우 YYYYMM으로 처리가 안되니 결과가 값은 NULL이 됩니다.
     (20180103 처리할수도 있겠지만.. 복잡해서요..)




 


by 마농 [2019.03.12 16:15:52]
WITH t AS
(
SELECT '2018' dt FROM dual
UNION ALL SELECT '201802'           FROM dual
UNION ALL SELECT '2018.2'           FROM dual
UNION ALL SELECT '2018.02'          FROM dual
UNION ALL SELECT '2018.02.13'       FROM dual
UNION ALL SELECT '2018-02'          FROM dual
UNION ALL SELECT '2018-02-13'       FROM dual
UNION ALL SELECT '2018/12'          FROM dual
UNION ALL SELECT '2019 1 1'         FROM dual
UNION ALL SELECT '2018/12/01'       FROM dual
UNION ALL SELECT '2019년 1월'       FROM dual
UNION ALL SELECT '2019년 1월 1일'   FROM dual
UNION ALL SELECT '2019년 01월 01일' FROM dual
UNION ALL SELECT '19년 1월 1일'     FROM dual
UNION ALL SELECT '99년 1월 1일'     FROM dual
UNION ALL SELECT '19년 13월 1일'    FROM dual
)
SELECT dt
     , TO_CHAR(TO_DATE(DECODE(gb, 1, x), 'rrrr-mm-dd'), 'yyyymmdd') x
  FROM (SELECT dt
             , CASE WHEN REGEXP_LIKE(x, '^[0-9]{4}-?[0-9]{1,2}$') THEN x||'-1'
                    WHEN REGEXP_LIKE(x, '^[0-9]{2}-?[0-9]{1,2}$') THEN x||'-1'
                    ELSE x END x
          FROM (SELECT dt
                     , RTRIM(REGEXP_REPLACE(dt, '[^0-9]+', '-'), '-') x
                  FROM t
                )
        )
     , XMLTABLE('if (. castable as xs:date) then 1 else 0' PASSING x COLUMNS gb NUMBER PATH '.')
;

 


by 오뚝이 [2019.03.12 16:52:20]

이렇게 심플하게 작성될 줄은 생각도 못했네요..
갓 마농님이시네요..^^
다시 한번 정규식 공부를 해야한다는걸 느낍니다.
xmltable은 처음 보는 문법인데.. 함께 찾아봐야겠어요..
마농님!
귀한 시간내어 도움주셔서 진심으로 감사드립니다.
남은 하루도 좋은 시간되세요..^^

댓글등록
SQL문을 포맷에 맞게(깔끔하게) 등록하려면 code() 버튼을 클릭하여 작성 하시면 됩니다.
로그인 사용자만 댓글을 작성 할 수 있습니다. 로그인, 회원가입