메뉴 건너뛰기

tnt_db

Oracle 그룹 단위별 일련번호 붙이기

운영자 2002.09.18 14:21 조회 수 : 5668 추천:12

그룹단위별 일련번호 붙이기

조건.
    TABLE : TEST11

    Name                            Null?    Type
    ------------------------------- -------- ----
    PRESS                           NOT NULL VARCHAR2(20)
    BOOK_TYPE                       NOT NULL VARCHAR2(20)
    BOOK_NAME                       NOT NULL VARCHAR2(20)
    PRICE                                    NUMBER

    위와같은 TABLE이 있다.

    PRESS       BOOK_TYPE  BOOK_NAME            PRICE
    ----------- ---------- -------------------- -----
    서울 출판사 소설       전원일기              9000
    서울 출판사 소설       인간시대              8000
    서울 출판사 소설       태백산               10000
    서울 출판사 소설       손자병법              7000
    서울 출판사 시         접시꽃당신            6000
    서울 출판사 시         진다래꽃              7000
    서울 출판사 시         윤동주시집            7000
    서울 출판사 시         겨울비                7000
    서울 출판사 수필       낙엽을태우며          7000
    서울 출판사 수필       가을이오면            7000
    서울 출판사 수필       어떻게사나            7000
    서울 출판사 수필       비오면나는님을그린다  7000
    한국출판    교과서     고교국어              9000
    한국출판    교과서     중학수학              8000
    한국출판    교과서     고교국어             10000
    한국출판    교과서     고교물리              7000
    한국출판    교과서     지구과학              6000
    한국출판    교과서     물리                  7000
    한국출판    교과서     고전                  7000
    한국출판    참고서     영어참고              7000
    한국출판    참고서     수학참고              7000
    한국출판    참고서     국어참고              7000
    한국출판    참고서     물리참고              7000
    한국출판    참고서     전과                  7000
    
    위와같은 DATA가 있으며 PRESS,BOOK_TYPE,BOOK_NAME 순으로
    UNIQUE INDEX 가 존재한다.
    PRESS 는 출판사이고 BOOK_TYPE 은 책의종류이다.
    출판사별로 나오는 책의 종류까지를 하나의 GROUP 단위로
    각 그룹별로 일련번호를 붙여서 DATA를 보고싶다.

문제. 다음과 같이 답이 나올수 있도로 QUERY를 작성하자.

    PRESS                BOOK_TYPE    RCNT
    -------------------- ------------ ----
    서울 출판사          소설            1
    서울 출판사          소설            2
    서울 출판사          소설            3
    서울 출판사          소설            4
    서울 출판사          수필            1
    서울 출판사          수필            2
    서울 출판사          수필            3
    서울 출판사          수필            4
    서울 출판사          시              1
    서울 출판사          시              2
    서울 출판사          시              3
    서울 출판사          시              4
    한국출판             교과서          1
    한국출판             교과서          2
    한국출판             교과서          3
    한국출판             교과서          4
    한국출판             교과서          5
    한국출판             교과서          6
    한국출판             교과서          7
    한국출판             참고서          1
    한국출판             참고서          2
    한국출판             참고서          3
    한국출판             참고서          4
    한국출판             참고서          5
    
생각.
    곰곰히 생각해보면 어려운문제는 아닌듯하다
    그룹지을 단위별로 1에서부터 COUNT를 세면된다.
    COUNT를 다시 시작하는 기준만을 정해주면된다.
    COUNT를 다시 시작한다는 것은 GROUP 단위가
    바뀌는 경우이다.
    GROUP 단위가 바뀌는것을 어떻게 알 수 있는가.
    전번 ROW의 COLUMN값을 이번 ROW와 비교해서
    이번 ROW의 COLUMN값이 달라졌으면 COUNT를 다시
    1부터 시작하면된다.
    문제는 이번 ROW가 GROUP단위중 몇번째인가하는 것이다.
    전번 ROW의 COUNT에 1을 더하면된다.
    그런데 전번 ROW는 자신이 GROUP단위중 몇번째인가에
    대한 정보를 가지고 있는가?...그렇지 않다.
    결국 전번ROW와 값을 비교한다는것은 가능은 하지만
    몇번째인지를 알수 있으려면 다른방법을 찾아야한다.
    엿보기1.각 그룹단위가 몇개의 RECORD를 가지고 있는가는 알수있다.
          그럼 거기서부터 문제를 다시풀어보자.
    엿보기2.각 그룹단위별로 COUNT(*)를 한값을 기준으로
          그 COUNT값 만큼만 DATA를 복제하면된다.
          그렇게 하면 결과가 어찌 나오겠는가.
          바로 위와같은 결과가 나온다.
해법.
    자주 사용하는 방법이지만 역시 DATA 복제가 열쇠다.
    단계1.먼저 PRESS,BOOK_TYPE 별로 COUNT 를 하면 다음과 같은
         결과가 나온다.

    PRESS            BOOK_TYPE   CNT
    ---------------- --------- -----      
    서울 출판사      소설          4
    서울 출판사      수필          4
    서울 출판사      시            4
    한국출판         교과서        7
    한국출판         참고서        5
    
    단계2.단계1의 결과를 각 그룹별 CNT 만큼 복제를 한다.
         문장은 다음과 같다.

        SELECT  A.PRESS,
                A.BOOK_TYPE,
                B.RCNT
        FROM
               (SELECT PRESS,BOOK_TYPE,COUNT(*) CNT
                FROM   TEST12
                GROUP BY
                       PRESS,BOOK_TYPE) A,     -- 단계1을 수행
               (SELECT ROWNUM RCNT
                FROM    TEST12)         B      -- 복제를 위한 DATASET
        WHERE B.RCNT    <= A.CNT               -- CNT 만큼 복제
        GROUP BY                               -- DATA의 정렬을 위해
              A.PRESS,
              A.BOOK_TYPE,
              B.RCNT
    문장을 실행시키면 위와같은 결과가 나온다.

뒷풀이.여기서 한가지 의문을 가질 수 있을 것이다.
    각 그룹단위별로 붙여진 순서가 실제 DATA 와 어떻게 연결될 수 있는가
    라는 문제이다.
    그렇다,그것도 문제가 될수 있다.
    하지만 우리가 방금 해결한 문제만으로도 충분히 가치있는 일을
    한 것이다.
    실제상황에서 필요한 경우가 얼마든지 있기때문이다.
    그렇다면 뒷풀이를 통해 실제 DATA와 연결짓는 방법을 생각해보자.
    단계1.위에서 도출된 결과는 이미 PRESS/BOOK_TYPE 순서로 정렬이
          이루어진 상태다.
          정렬된 순서대로 번호를 붙여준다면 어떻겠는가.
    단계2.가능한 일이다.
          그리고 원 TABLE에 있는 DATA를 동일한 순서로 읽어오되
          앞에 ROWNUM을 붙여서 읽어오면 두 DATASET이 ROWNUM
          만으로 연결이 가능하다.
    한번 직접 해보자.
    답은 아래와같다.

    SELECT G1_1.RNUM,
           G1_1.PRESS,
           G1_1.BOOK_TYPE,
           G2_1.BOOK_NAME,
           G1_1.RCNT
    FROM
       (SELECT ROWNUM RNUM,
               G1.PRESS,
               G1.BOOK_TYPE,
               G1.RCNT
        FROM                            
           (SELECT  A.PRESS,
                    A.BOOK_TYPE,
                    B.RCNT
            FROM
                   (SELECT PRESS,BOOK_TYPE,COUNT(*) CNT
                    FROM   TEST12
                    GROUP BY
                           PRESS,BOOK_TYPE) A,
                   (SELECT ROWNUM RCNT
                    FROM    TEST12)         B
            WHERE B.RCNT    <= A.CNT
            GROUP BY
                  A.PRESS,
                  A.BOOK_TYPE,
                  B.RCNT
            )  G1                        -- 해답에서 제시한 답
        ) G1_1,                          -- 그결과에 ROWNUM 붙임(A)
        (SELECT ROWNUM RNUM,
                PRESS,
                BOOK_TYPE,
                BOOK_NAME
         FROM   TEST12
         WHERE PRESS > ' '               -- INDEX COLUMN이 조건에 사용
                                         -- 되어 INDEX순서로 DATA SCAN
        ) G2_1                           -- 원래의 DATA를 동일한 순서로        
                                         -- 읽어서 ROWNUM 붙임(B)
    WHERE G1_1.RNUM = G2_1.RNUM          -- (A)와 (B) JOIN

    결과는 다음과 같다.

     1  서울 출판사    소설         손자병법             1
     2  서울 출판사    소설         인간시대             2
     3  서울 출판사    소설         전원일기             3
     4  서울 출판사    소설         태백산               4
     5  서울 출판사    수필         가을이오면           1
     6  서울 출판사    수필         낙엽을태우며         2
     7  서울 출판사    수필         비오면나는님을그린다 3
     8  서울 출판사    수필         어떻게사나           4
     9  서울 출판사    시           겨울비               1
    10  서울 출판사    시           윤동주시집           2
    11  서울 출판사    시           접시꽃당신           3
    12  서울 출판사    시           진다래꽃             4
    13  한국출판       교과서       고교국어             1
    14  한국출판       교과서       고교물리             2
    15  한국출판       교과서       고교수학             3
    16  한국출판       교과서       고전                 4
    17  한국출판       교과서       물리                 5
    18  한국출판       교과서       중학수학             6
    19  한국출판       교과서       지구과학             7
    20  한국출판       참고서       국어참고             1
    21  한국출판       참고서       물리참고             2
    22  한국출판       참고서       수학참고             3
    23  한국출판       참고서       영어참고             4
    24  한국출판       참고서       전과                 5
사족.
    여러용도로 활용 가능한 방법이다.
    특히 REPORT FORMAT 에 맞추는 QUERY에서 유용하게
    쓰일 수 있다.
위로