조건.
TEST37 에 다음과 같은 DATA가 있다.
DATA
----------
0000
0003
0006
0010
0013
문제.
중간에 빠진값만을 읽어오는 문제다.
결과는 다음과 같이 나오면 된다.
DATA
-----
0001
0002
0004
0005
0007
0008
0009
0011
0012
이미 앞에서 다뤄본 문제이다.
똑같은 유형의 문제를 다시 다루는 이유는 해법을 약간 달리
해보자는 것이다.
앞 주제에서 이 문제를 풀때 우리는 MINUS 라는 집합 연산자를
이용했다.
이번에는 MINUS 집합연산자를 이용하지 않고,SELF JOIN을 이용한다.
앞주제에서는 DATA의 최대 ROW수보다 크거나 같은 ROW수를
가지고 있는 TABLE이 반드시 존재를 하고 있어야 했다.
만약 TEST37의 DATA FIELD 의 최대값이 매우커서 그 최대값보다
많은 ROW수를 가진 TABLE이 없을때는 지난번 해법으로는
해결 불가능하다.
ROW수가 충분히 많아서 조건을 만족시켜줄 수 있는 그런 TABLE을
새로 만들어 주지 않는한.
이번 문제를 통해서는 그 위험을 줄여주자는 것이다.
힌트를 준다면 최대값보다 크거나 같은 ROW수를 가진 TABLE을
찾을 필요가 없이,
중간에 빠진 이빨의 차이가 가장 큰 수 보다 많거나 같은 ROW만
가진다면 문제를 해결할 수 있는 QUERY 를 요구하고 있는 것이다.
만약 DATA가 1,3,8,10 과 같이 들어 있다면 빠진 이빨 차이가
가장 큰 값은 8과 3의 차이인 5 이다.
위험을 완전히 없애지는 못했지만 많이 줄일 수는 있다.
만약 최대값이 매우큰 DATA 이면서 빠진 이빨의 차이가 매우커서
그 차이보다 많은 ROW수를 가진 TABLE이 없다면 이번 방법으로도
해결할 수 없다.
그때는 또 다른 방법을 찾아야 할 것이다.
생각.
이 문제에서 요구하는 해법은 다음과 같다.
먼저 DATA를 바로전 RECORD 값과 비교해서 차이가 1보다 큰 DATA만
찾아내고,
그 (차이값-1) 만큼을 LOOP 을 돌면서 전 RECORD의 값을 기준으로
1씩 증가시켜 값을 만들어 낸다.
문제에 주어진 DATA를 이용해 보면 다음과 같다.
DATA 바로전값
---------- ----------
0
3 0
6 3
10 6
13 10
DATA 값이 3인 경우를 보면 3과 0의 차이는 3 이다.
이경우 차이가 1보다 크므로 차이나는 만큼(3-1=2)번 LOOP을
돌며 전값을 기준으로 1씩 증가 시키면 0+1,0+2 가 되어 1,2 가
RETURN 된다.
다른 값도 마찬가지로 적용된다.
위와 같은 방법으로 문제를 해결한다.
해법.
단계1.위의 방법을 적용하기 위하여 가장먼저 해야 할 일은 바로
전값을 해당 DATA에 MATCH 시키는 일이다.
TABLE 을 읽을 때 ROWNUM을 붙여서 읽은 똑 같은 두개의
DATASET을 아래와 같이 비교한다.
SELECT B.DATA DATA1,A.DATA DATA2
FROM
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') A,
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') B
WHERE A.RNUM(+) = B.RNUM - 1
참고로 DATA COLUMN 에는 INDEX가 존재한다.
그럴경우 결과는 아래와 같다.
DATA1 DATA2
---------- ----------
0
3 0
6 3
10 6
13 10
단계2.다음으로 할 일은 위의 DATASET을 이용하여 두 값의 차이가
1보다 큰 ROW 들을 찾아내는 일이다.
위의 DATASET을 INLINE VIEW로 이용하여 다음과 같은
QUERY를 만든다.
SELECT DATA1,DATA2
FROM (SELECT B.DATA DATA1,A.DATA DATA2
FROM
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') A,
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') B
WHERE A.RNUM(+) = B.RNUM - 1) A
WHERE A.DATA1 - A.DATA2 > 1
결과는 아래와 같이 된다.
DATA1 DATA2
---------- ----------
3 0
6 3
10 6
13 10
단계3.마지막으로 LOOP을 돌면서 1씩 증가시키는 과정이다.
완벽한 LOOP을 지원하지 않지만 QUERY에서 LOOP이라는 것은
결국 조인이다.
FROM 절에 "(SELECT ROWNUM RNUM FROM USER_TABLES) B"를
추가하고,
WHERE 절에 "AND B.RNUM < A.DATA1 - A.DATA2" 를
추가한다.
그리고 SELECT 절을 "TO_CHAR(DATA2+RNUM,'0000')"
로 바꿔준다.
그러면 최종 문장이 이렇게 된다.
SELECT TO_CHAR(DATA2+RNUM,'0000') DATA
FROM (SELECT B.DATA DATA1,A.DATA DATA2
FROM
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') A,
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') B
WHERE A.RNUM(+) = B.RNUM - 1) A,
(SELECT ROWNUM RNUM FROM USER_TABLES) B
WHERE A.DATA1 - A.DATA2 > 1
AND B.RNUM < A.DATA1 - A.DATA2
여기서 조건은 USER_TABLE에 있는 ROW수가 TEST37의 DATA가
가지는 차이들의 최대값보다 크거나 같아야 한다는 것이다.
뒷풀이.
전번 "빠진이빨찾기" 주제의 해법이 가졌던 한계를 보완하긴 했지만,
위에서 언급했듯이 이번 해법도 한계를 안고 있다.
충분히 많은 ROW를 가지는 TABLE을 새로 만들면 되지만
그렇게 하지 않고 해법을 구하고자 한다면
FROM절의 "(SELECT ROWNUM RNUM FROM USER_TABLES)" 부분을
수정해야 한다.
해당부분에서 UNION 이나 JOIN 을 이용해 충분히 많은 ROW를
뒷받침 해줄 수 있도록 하는 것이 최선의 방법이 아닌가 한다.
TEST37 에 다음과 같은 DATA가 있다.
DATA
----------
0000
0003
0006
0010
0013
문제.
중간에 빠진값만을 읽어오는 문제다.
결과는 다음과 같이 나오면 된다.
DATA
-----
0001
0002
0004
0005
0007
0008
0009
0011
0012
이미 앞에서 다뤄본 문제이다.
똑같은 유형의 문제를 다시 다루는 이유는 해법을 약간 달리
해보자는 것이다.
앞 주제에서 이 문제를 풀때 우리는 MINUS 라는 집합 연산자를
이용했다.
이번에는 MINUS 집합연산자를 이용하지 않고,SELF JOIN을 이용한다.
앞주제에서는 DATA의 최대 ROW수보다 크거나 같은 ROW수를
가지고 있는 TABLE이 반드시 존재를 하고 있어야 했다.
만약 TEST37의 DATA FIELD 의 최대값이 매우커서 그 최대값보다
많은 ROW수를 가진 TABLE이 없을때는 지난번 해법으로는
해결 불가능하다.
ROW수가 충분히 많아서 조건을 만족시켜줄 수 있는 그런 TABLE을
새로 만들어 주지 않는한.
이번 문제를 통해서는 그 위험을 줄여주자는 것이다.
힌트를 준다면 최대값보다 크거나 같은 ROW수를 가진 TABLE을
찾을 필요가 없이,
중간에 빠진 이빨의 차이가 가장 큰 수 보다 많거나 같은 ROW만
가진다면 문제를 해결할 수 있는 QUERY 를 요구하고 있는 것이다.
만약 DATA가 1,3,8,10 과 같이 들어 있다면 빠진 이빨 차이가
가장 큰 값은 8과 3의 차이인 5 이다.
위험을 완전히 없애지는 못했지만 많이 줄일 수는 있다.
만약 최대값이 매우큰 DATA 이면서 빠진 이빨의 차이가 매우커서
그 차이보다 많은 ROW수를 가진 TABLE이 없다면 이번 방법으로도
해결할 수 없다.
그때는 또 다른 방법을 찾아야 할 것이다.
생각.
이 문제에서 요구하는 해법은 다음과 같다.
먼저 DATA를 바로전 RECORD 값과 비교해서 차이가 1보다 큰 DATA만
찾아내고,
그 (차이값-1) 만큼을 LOOP 을 돌면서 전 RECORD의 값을 기준으로
1씩 증가시켜 값을 만들어 낸다.
문제에 주어진 DATA를 이용해 보면 다음과 같다.
DATA 바로전값
---------- ----------
0
3 0
6 3
10 6
13 10
DATA 값이 3인 경우를 보면 3과 0의 차이는 3 이다.
이경우 차이가 1보다 크므로 차이나는 만큼(3-1=2)번 LOOP을
돌며 전값을 기준으로 1씩 증가 시키면 0+1,0+2 가 되어 1,2 가
RETURN 된다.
다른 값도 마찬가지로 적용된다.
위와 같은 방법으로 문제를 해결한다.
해법.
단계1.위의 방법을 적용하기 위하여 가장먼저 해야 할 일은 바로
전값을 해당 DATA에 MATCH 시키는 일이다.
TABLE 을 읽을 때 ROWNUM을 붙여서 읽은 똑 같은 두개의
DATASET을 아래와 같이 비교한다.
SELECT B.DATA DATA1,A.DATA DATA2
FROM
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') A,
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') B
WHERE A.RNUM(+) = B.RNUM - 1
참고로 DATA COLUMN 에는 INDEX가 존재한다.
그럴경우 결과는 아래와 같다.
DATA1 DATA2
---------- ----------
0
3 0
6 3
10 6
13 10
단계2.다음으로 할 일은 위의 DATASET을 이용하여 두 값의 차이가
1보다 큰 ROW 들을 찾아내는 일이다.
위의 DATASET을 INLINE VIEW로 이용하여 다음과 같은
QUERY를 만든다.
SELECT DATA1,DATA2
FROM (SELECT B.DATA DATA1,A.DATA DATA2
FROM
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') A,
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') B
WHERE A.RNUM(+) = B.RNUM - 1) A
WHERE A.DATA1 - A.DATA2 > 1
결과는 아래와 같이 된다.
DATA1 DATA2
---------- ----------
3 0
6 3
10 6
13 10
단계3.마지막으로 LOOP을 돌면서 1씩 증가시키는 과정이다.
완벽한 LOOP을 지원하지 않지만 QUERY에서 LOOP이라는 것은
결국 조인이다.
FROM 절에 "(SELECT ROWNUM RNUM FROM USER_TABLES) B"를
추가하고,
WHERE 절에 "AND B.RNUM < A.DATA1 - A.DATA2" 를
추가한다.
그리고 SELECT 절을 "TO_CHAR(DATA2+RNUM,'0000')"
로 바꿔준다.
그러면 최종 문장이 이렇게 된다.
SELECT TO_CHAR(DATA2+RNUM,'0000') DATA
FROM (SELECT B.DATA DATA1,A.DATA DATA2
FROM
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') A,
(SELECT ROWNUM RNUM,TO_NUMBER(DATA) DATA
FROM TEST37 WHERE DATA > ' ') B
WHERE A.RNUM(+) = B.RNUM - 1) A,
(SELECT ROWNUM RNUM FROM USER_TABLES) B
WHERE A.DATA1 - A.DATA2 > 1
AND B.RNUM < A.DATA1 - A.DATA2
여기서 조건은 USER_TABLE에 있는 ROW수가 TEST37의 DATA가
가지는 차이들의 최대값보다 크거나 같아야 한다는 것이다.
뒷풀이.
전번 "빠진이빨찾기" 주제의 해법이 가졌던 한계를 보완하긴 했지만,
위에서 언급했듯이 이번 해법도 한계를 안고 있다.
충분히 많은 ROW를 가지는 TABLE을 새로 만들면 되지만
그렇게 하지 않고 해법을 구하고자 한다면
FROM절의 "(SELECT ROWNUM RNUM FROM USER_TABLES)" 부분을
수정해야 한다.
해당부분에서 UNION 이나 JOIN 을 이용해 충분히 많은 ROW를
뒷받침 해줄 수 있도록 하는 것이 최선의 방법이 아닌가 한다.
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
34 | 반올림 DATA의 오차보정 | 운영자 | 2002.09.18 | 3585 |
33 | 복제를이용한 합계계에서 비율계산 | 운영자 | 2002.09.18 | 3669 |
32 | DATA변환 | 운영자 | 2002.09.18 | 2750 |
31 | 중간값구하기 | 운영자 | 2002.09.18 | 3377 |
30 | 한번 읽은 테이블로 백분율 구하기 | 운영자 | 2002.09.18 | 4085 |
29 | 빠진이빨찾기 III | 운영자 | 2002.09.18 | 3359 |
» | 빠진이빨찾기 II | 운영자 | 2002.09.18 | 3067 |
27 | 빠진이빨찾기 | 운영자 | 2002.09.18 | 3122 |
26 | 순환참조에서의 상위코드로집계 | 운영자 | 2002.09.18 | 3226 |
25 | CONNECT BY의 SORT와 JOIN | 운영자 | 2002.09.18 | 2811 |
24 | REPORT 양식맞추기4 | 운영자 | 2002.09.18 | 2597 |
23 | REPORT 양식 맞추기 III | 운영자 | 2002.09.18 | 3015 |
22 | REPORT 양식 맞추기 II | 운영자 | 2002.09.18 | 2646 |
21 | REPORT 양식 맞추기 | 운영자 | 2002.09.18 | 31359 |
20 | 1:1 JOIN / 1:M JOIN | 운영자 | 2002.09.18 | 3000 |
19 | TUNING-01 | 운영자 | 2002.09.18 | 2739 |
18 | 소계와 합계 | 운영자 | 2002.09.18 | 3489 |
17 | 중복DATA 찾아내기 | 운영자 | 2002.09.17 | 2817 |
16 | GROUP별 DATA 분류 | 운영자 | 2002.09.17 | 2982 |
15 | PARAMETER값에 따라 변경이 일어나는 문장 | 운영자 | 2002.09.17 | 15808 |