메뉴 건너뛰기

tnt_db

Oracle 빠진이빨찾기

운영자 2002.09.18 13:28 조회 수 : 3122 추천:11

CREATE TABLE TEST(A VARCHAR2(08) NOT NULL , B NUMBER NOT NULL,
                  CONSTRAINT TEST_PK PRIMARY KEY (A,B)
                 );
INSERT INTO TEST VALUES ('19981113',1);
INSERT INTO TEST VALUES ('19981113',2);
INSERT INTO TEST VALUES ('19981113',4);
INSERT INTO TEST VALUES ('19981113',5);
INSERT INTO TEST VALUES ('19981113',6);
INSERT INTO TEST VALUES ('19981113',8);
INSERT INTO TEST VALUES ('19981113',11);
INSERT INTO TEST VALUES ('19981114',1);
INSERT INTO TEST VALUES ('19981114',2);
INSERT INTO TEST VALUES ('19981114',5);
INSERT INTO TEST VALUES ('19981114',6);
INSERT INTO TEST VALUES ('19981114',7);
INSERT INTO TEST VALUES ('19981114',8);





빠진 이빨 찾기

조건.
    TEST TABLE에 DATA가 다음과 같이 들어있다.

    A        B        
    -------- ----------
    19981113          1
    19981113          2
    19981113          4
    19981113          5
    19981113          6
    19981113          8
    19981113         11
    19981114          1
    19981114          2
    19981114          5
    19981114          6
    19981114          7
    19981114          8
문제.
    이번 문제는 창원대 HOMEPAGE에 올라온 질문을 본인이
    답을 달아준 문제다.
    질문의 요지는 다음과 같다.
    A COLUMN 에 대해 B가 정수로 숫자를 가지는데
    각 A값에 대해 B의 1에서 최대값 사이의 값중 빠져있는 값을
    읽어 내면된다.
    19981113 에 대해서는 3,7,9,10 이 빠져있으며,
    19981114 에 대해서는 3,4 가 빠져있다.

    결과를 다음과 같이 보여주면 된다.

    A        B        
    -------- ----------
    19981113          3
    19981113          7
    19981113          9
    19981113         10
    19981114          3
    19981114          4

생각.
    여러가지 방법을 쓸 수 있겠지만 여기서 사용한 방법은 간단하다.
    우선 각 A 값에 대해 입력되어 있는 최대값을 찾는다. 그리고
    1부터 최대값 사이의 빈자리를 모두 채워주는 DATASET을 만들어낸 후
    거기에서 TABLE에 존재하는 DATA를 빼는 방법 을 사용했다.
    문제는 각 A 값에 대해 최대값이 항상 일정하지 않다는 것이다.
    그렇다면 모든 A 값에 대해 그 값이 가진 최대 숫자를 알고 있어야
    한다는 결론이 나온다.
    그런후 각각의 A값 에대해 1에서 부터 그 최대값까지를 복제한 후
    그 복제번호를 B값 대용으로 사용한다.
    복제가 A값이 가진 MAX(B) 만큼 일어나면된다.
    그렇게 이빨이 빠지지 않은 완벽한 DATASET이 만들어지면
    MINUS 라는 집합 연산용 연산자를 이용해 TABLE에 있는 실제
    DATA 를 빼내면 된다.

해법.
    단계1.TEST에 존재하는 각각의 A 값에 대해 그들이 가지고 있는 MAX(B)
          를 읽어 온다. A 에 대해 GROUP BY 하면 된다.
          이때 우리는 JOIN조건에서 "<=" 아닌 "<" 비교를 하기위하여
          MAX(B)+1 을 읽어온다.
          물론 "<=" 비교를 한다면 그냥 MAX(B) 라고 읽어도 무방하다.
          
          SELECT A,MAX(B)+1 VAL FROM TEST GROUP BY A
          현재 상태에서의 결과는 다음과 같다.

          A        VAL      
          -------- ----------
          19981113         12
          19981114          9
    단계2.다음으로 할일은 복제를 하기위한 DATASET을 만든다.
          우리가 흔히 사용하듯이 USER_TABLES 에서 ROWNUM을 읽어온다.
          물론 USER_TABLE 에는 위의 문제를 해결할 만큼의 충분한 ROW가
          존재해야 한다.
          그렇지 않다면 만족할 만한 충분한 ROW를 가진 TABLE을
          아무거나 이용한다.
    단계3.1번과 2번의 DATASET을 아까 언급한대로 연결한다.                  
          1번 DATASET을 T1 이라하고,2번 DATASET을 T2라고 하면
          조건식이 아래와 같을 것이다.
                  
          WHERE  T2.R_CNT < T1.VAL
    단계4.지금까지의 결과를 살펴보자.
          SELECT T1.A,
                 T2.R_CNT
          FROM  (SELECT A,MAX(B)+1 VAL FROM TEST GROUP BY A) T1,
                (SELECT ROWNUM R_CNT FROM USER_TABLES) T2
          WHERE  T2.R_CNT < T1.VAL

          A        B        
          -------- ----------
          19981113          1
          19981113          2
          19981113          3
          19981113          4
          19981113          5
          19981113          6
          19981113          7
          19981113          8
          19981113          9
          19981113         10
          19981113         11
          19981114          1
          19981114          2
          19981114          3
          19981114          4
          19981114          5
          19981114          6
          19981114          7
          19981114          8

          빠진 이빨이 없다.
    단계5.마지막으로 위의 DATASET 에서 TEST 에 존재하는 값을 빼내자.
          SELECT T1.A,
                 T2.R_CNT
          FROM  (SELECT A,MAX(B)+1 VAL FROM TEST GROUP BY A) T1,
                (SELECT ROWNUM R_CNT FROM USER_TABLES) T2
          WHERE  T2.R_CNT < T1.VAL
          MINUS
          SELECT A,B FROM TEST
    
          문제에서 요구한 결과를 만들어주는 답이다.
뒷풀이.
   B 가 정수가 아닌 코드라 해도 그 코드가 관리되는 TABLE만 존재한다면
   위와 같은 결과를 가져올 수 있다.

번호 제목 글쓴이 날짜 조회 수
46 빠진이빨찾기 II 운영자 2002.09.18 3067
» 빠진이빨찾기 운영자 2002.09.18 3122
44 순환참조에서의 상위코드로집계 운영자 2002.09.18 3226
43 CONNECT BY의 SORT와 JOIN 운영자 2002.09.18 2811
42 REPORT 양식맞추기4 운영자 2002.09.18 2597
41 REPORT 양식 맞추기 III 운영자 2002.09.18 3015
40 REPORT 양식 맞추기 II 운영자 2002.09.18 2646
39 REPORT 양식 맞추기 운영자 2002.09.18 31359
38 1:1 JOIN / 1:M JOIN 운영자 2002.09.18 3000
37 TUNING-01 운영자 2002.09.18 2739
36 소계와 합계 운영자 2002.09.18 3489
35 중복DATA 찾아내기 운영자 2002.09.17 2817
34 GROUP별 DATA 분류 운영자 2002.09.17 2982
33 PARAMETER값에 따라 변경이 일어나는 문장 운영자 2002.09.17 15808
32 SELF JOIN 운영자 2002.09.17 3408
31 Outer Join 운영자 2002.09.17 2918
30 HINTS (출처-Oracle8.0 Tuning Guide) 운영자 2002.09.17 2735
29 단일행 문자 함수 운영자 2002.09.17 2977
28 단일행 수치 함수 운영자 2002.09.17 2869
27 NOT IN 의 함정 운영자 2002.09.17 2713
위로