메뉴 건너뛰기

tnt_db

Oracle 중간값구하기

운영자 2002.09.18 13:47 조회 수 : 3377 추천:19

문제.
    PARAMETER 로 FROM 월과 TO월이 주어지면 해당월 사이의 월을    
    모두 구해내는 문제이다.
    즉 시작월로 '199906' 이 주어지고 마지막월로 '200004' 가 주어진다면
    
    RNUM       TIT
    ---------- ----------------
             1 1999.06
             2 1999.07
             3 1999.08
             4 1999.09
             5 1999.10
             6 1999.11
             7 1999.12
             8 2000.01
             9 2000.02
            10 2000.03
            11 2000.04

    와 같은 결과를 만들어 내는 것이다.
    시작월과 마지막월 PARAMETER 대신 각각 '199906' 과 '200004'를
    사용한다.

생각.
    기간을 가져오기 위해 몇년분의 일자나 또는 몇년분의 월만을 따로
    보관하는 경우를 흔히 볼수 있다.
    단순히 조건으로 주어진 기간내의 일이나 월이 필요해서 그 값을
    읽어오기 위해서다.
    그것이 나쁘다는 얘기는 아니지만 그렇게 TABLE까지 만들어서
    관리하지 않아도 값을 읽을 수 있는 방법을 알아보기 위해서다.
    RNUM 이라는 값은 참조용이고 실제로 구하기를 원하는 값은
    결과에서 나타난 TIT 값이다.
    위의 결과를 가만히 살펴보면 다음과 같은 정보를 얻어낼 수
    있을 것이다.
    첫번째 TIT 값은 시작월로 들어온 값 그대로이고,
    두번째는 1달을 더한값,
    세번째는 2달을 더한값, N번째는 N-1을 더한값 이라는 것을.
    가볍게 해결할 수 있는 문제이다.
    문제를 푸는 핵심은 역시 ROWNUM 이다.
    주어지는 기간을 ROW수로 환산했을때 그 최대값을 충분히
    수용할 수 있는 만큼의 ROW를 가진 TABLE에서 ROWNUM을 읽어온다.
    다음으로
    읽어온 ROWNUM중 기간값에 들어가는 수만큼을 조건절에서 걸러낸다.
    기간값이 2월부터 12월 이면 11개의 월이 필요하므로 ROWNUM중
    1번부터 11번까지만을 읽어오는 식이다.
    그렇게 한 후 시작월에 ROWNUM-1 만큼씩 월을 더해가면 된다.
    이때 함수 ADD_MONTHS 를 이용한다.

해법.
    단계1.
        SELECT ROWNUM
        FROM  (SELECT ROWNUM RNUM FROM USER_TABLES)
        
        처럼 기술하면 USER_TABLES에 있는 ROW 수 만큼의 번호를
        RNUM 이라는 이름으로 가져오게 된다.  
        이 중에서 기간사이에 해당하는 ROW 수 만큼 제한을 두는 방법을
        생각해 보자.
        문제의 경우는 1에서 11까지를 가져와야 하기때문에 RNUM < 12
        와 같이 조건을 주면 된다.
        '200004' 와 '199906'을 이용해서 12 또는 11 이라는 값을
        만들어 낼 수 있는가?.
        DATE 로 형 변환한 후 월에서 월을 빼면 그 사이의
        일자수가 나온다.
        그값을 이용해 한달을 30일 이라고 가정하고 30 으로 나눈후
        그보다 큰 정수 값을 받는 것도 한가지 방법이다.
        CEIL((TO_DATE(200010,'YYYYMM') - TO_DATE(199912,'YYYYMM'))/30)
        처럼
        문제는 없겠지만 그 값이 의심스러우면 다음과 같은 방법을
        이용해 보자.

        WHERE ADD_MONTHS(TO_DATE('199906','YYYYMM'), RNUM -1 ) <=  
              TO_DATE('200004','YYYYMM')
  
        위와같이 하면 확실한 값을 얻을 수 있다.

   단계2.문제는 다 해결되었다.
        이제 SELECT 절에 시작월 + RNUM - 1 만큼 을 읽어 오도록 기술한다.
        이렇게
        TO_CHAR(ADD_MONTHS(TO_DATE('199906','YYYYMM'),RNUM-1),'YYYY.MM')
        최종 문장은 아래와 같다.
  
        SELECT RNUM,
               TO_CHAR(ADD_MONTHS(TO_DATE('199906','YYYYMM'),
                         RNUM -1 ),'YYYY.MM')
        FROM  (SELECT ROWNUM RNUM FROM USER_TABLES)
        WHERE  ADD_MONTHS(TO_DATE('199906','YYYYMM'), RNUM -1 ) <=
               TO_DATE('200004','YYYYMM')

        여기에서 강제로 주어진 시작값과 끝값을 PARAMETER 값으로

        바꾸면 상황에 따라 유용하게 쓰일 수 있을 것이다.

위로