조건.
T100 에 다음과 같은 DATA가 들어있다.
C1 C2
------ ----------
A 10
B 20
C 30
D 40
E 50
문제.
T100 TABLE의 ACCESS 가 한번만 허용된 상태라고 할때
- 실제로 ACCESS가 한번만 허용될리는 없다.
단지 조건이 복잡하다거나
INDEX가 존재하지 않는다거나 하는 여러가지 이유로 두번 읽는것이
부담스러울 경우가 있다. -
MAIN TABLE인 T100 을 한번만 읽은 후 가공을 통하여 백분율을
구해내는 문제다.
결과 가 다음처럼 나오면 된다.
C1 C2 C2_RT
------ ---------- ----------
A 10 6.67
B 20 13.33
C 30 20
D 40 26.67
E 50 33.33
대부분의 경우는 오히려 이문제에서 요구하는 답보다
차라리 TABLE을 한번 더 ACCESS 하여 미리 합을 구해놓고 그 값을
이용해 백분율을 구하는 방법이 쓰기 간편하고 효과도 뛰어나다.
생각.
이 문제를 주어진 환경 안에서 해결하기 위해 가장먼저 고려 되어야
할 것은 이제까지 우리가 이용했던 복제이다.
복제를 하기위해 여태까지 우리는 복제용 테이블을 이용하지 않았다.
그 이유는 여태까지 우리가 다루었던 주제에서는 주어진 DATA의
샘플이 그 원리 만을 설명하기에 충분할 만큼만 주어졌기 때문이다.
하지만 DATA가 매우 많아져서 많은 양의 복제가 일어나야 한다면
- 그런 경우도 그리 흔하지 않지만
이번 예제가 그런 경우가 될 수 있다 -
복제를 하기위해 많은 ROW수를 가진 TABLE에서 ROWNUM을 읽어오는
방식 보다는 INDEX가 생성되어 있는 복제전용 테이블을 이용하는
것이 효율적일 수 있다.
다시 문제를 해결하기 위한 방법으로 돌아와서 생각하자.
복제가 어떻게 이용될 것인가는 차차 얘기하고 가장 급선무는 역시
읽어 온 DATA의 전체 합계를 알아야 백분율을 구할 수 있다는 얘기다.
전체합계 역시 복제를 이용해 구한다.
전체 합계를 구하는 문제는 여러번 접해 봤기에 더 이상
설명하지 않겠다.
전체합계를 구한 후 그 값을 전체 ROW 수 만큼 복제하여 각
ROW 마다 하나씩 MATCH 시켜주는 단계를 밟는다.
이때 백율율 계산 대상이 되는 전체 ROW수도 필요하다는 것을
알 수 있다.
그래야지만 그 수만큼 복제를 할 수 있기 때문이다.
그리고 각 ROW와 그 ROW에 연결될 합계 값을 MATCH 시켜줄 GROUPING
조건을 찾는 것이 문제를 해결하는 가장 중요한 열쇠다.
그렇게 하고 나면 애초 DATA의 값과 합계값을 이용해 백분율을 구하는
것은 산수다.
해법.
항상 말로는 설명이 어렵다.
직접 예제를 통해 알아보자.
단계1.위에서 언급 되었듯이 첫 단계에서 필요한 정보요소를
나열하면
다음과 같다.
C1 : KEY 역할을 하므로 언제나 필요한 정보다.
C2 : 백분율을 구할때 분자가 된다
합계 : 백분율을 구할때 분모가 된다
ROW수 : 합계를 ROW수 만큼 복제하는 단계에서 유용하게
쓰일 정보다.
한가지 염두에 둘 것은 이번 단계에서 합계가 나오긴 하지만
그 합계가 하나의 ROW값으로 나온다는 것이다.
뒤에 그 하나의 ROW를 복제하여 각각의 ROW와 연결 지어 줄
것이다.
SELECT COUNT(B.NO) CNT, <- ROW수
MIN(DECODE(B.NO, 1, A.C1)) C1, <- C1(합계는 C1에 NULL)
SUM(A.C2) C2 <- C2(합계)
FROM T100 A,
(SELECT ROWNUM NO FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)
CNT C1 C2
---------- ------ ----------
1 A 10
1 B 20
1 C 30
1 D 40
1 E 50
5 150
위의 문장은 바로위와 같은 결과를 RETURN 한다.
여기서 마지막 ROW가 합계를 가지고 있는 ROW이며,
원래 DATA의 ROW수에 대한 정보도 가지고 있는 RECORD 이다.
단계2.위의 상태에서 CNT에 나타난 숫자 만큼만 각 ROW를 복제한다.
합계정보를 가지고 있는 마지막 ROW만 5번 복제가 되어 나오며
나머지는 한번의 복제가 일어나므로 결국 자신의 값을 그대로
가지게 된다.
이단계가 바로 다량의 복제를 일으킬 수 있는 부분이다.
현재는 ROW수가 5개밖에 없어서 5번의 복제가 일어나지만,
건수가 많아진다면,INDEX가 걸린 복제전용 TABLE을 쓰느냐
그렇지않고 ROW가 그보다 많은 TABLE에서 ROWNUM을
채취하여 쓰느냐 에 따라 엄청난 속도의 차이를 가져온다.
현재의 문제에서는 DATA 가 몇건 안되므로 ROWNUM을 채취하여
사용 하겠다.
복제를 한 후 다음과 같은 정보를 보자.
NO : 복제번호
ROWNUM : 복제후의 ROWNUM
CNT : 합계를 구할때의 CNT
C1,C2
SELECT NO,ROWNUM,CNT,C1,C2
FROM (SELECT COUNT(B.NO) CNT,
MIN(DECODE(B.NO, 1, A.C1)) C1,
SUM(A.C2) C2
FROM T100 A,
(SELECT ROWNUM NO
FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)) X,
(SELECT ROWNUM NO FROM USER_TABLES) Y
WHERE Y.NO <= X.CNT
NO ROWNUM CNT C1 C2
---------- ---------- ---------- ------ ----------
1 1 1 A 10
1 2 1 B 20
1 3 1 C 30
1 4 1 D 40
1 5 1 E 50
1 6 5 150
2 7 5 150
3 8 5 150
4 9 5 150
5 10 5 150
위의 결과를 살펴보면 원 DATA의 ROW수 와 합계값을 가진
ROW수가 서로 같다는 것을 알 수 있다.
그렇다면 DATA 하나에 합계를 하나씩 연결해주는 작업을 해보자.
다음 단계는 두개(각 DATA와 합계)에 같은 GROUP 단위를
주어주고 GROUP BY 하는 것이다.
먼저 연결을 위한 동일 GROUP 단위 부여를 위해 위의 결과를
자세히 살펴보자.
모든 RECORD는 ROWNUM이 1부터 차례로 주어져 있다.
그리고 합계는 NO가 1부터 다시 주어져 있다.
한가지 문제가 된다면 합계값을 가지는 ROW들이 1부터 다시
시작되지만,
합계가 아닌 원 DATA의 NO 값은 모두 1이라는 것이다.
즉,첫번째 합계를 나타내는 NO 1 이 원DATA의 NO 1과 구분이
되어져야 한다는 것이다.
하지만 그것도 그리 큰 문제점은 아니다.
CNT 가 가진 정보를 보면 그 ROW가 원래 DATA인지 아니면
합계용 DATA 인지를 쉽계 구분할 수 있기 때문이다.
단계3.최종적으로 보여야 될 정보는 C1,C2,그리고
DATA/(DATA의 ROWNUM과 같은 NO를 가진 합계)*100 이다.
DATA 와 (DATA의 ROWNUM과 같은 NO를 가진 합계) 를
하나의 ROW로 묶기위해 GROUP BY할 단위는 이미 정해졌다.
CNT 가 1이면 ROWNUM을 아니면 NO 를 GROUPING 단위로
주어주면 같은 GROUPING 단위를 갖는 ROW가 DATA 1개 ,
합계 1개 씩
총 두개씩이 생긴다.
QUERY를 다시 다음과 같이 바꿔보자.
SELECT DECODE(X.CNT, 1, ROWNUM,Y.NO) GRP_UNIT,
C1,
C2
FROM (SELECT COUNT(B.NO) CNT,
MIN(DECODE(B.NO, 1, A.C1)) C1,
SUM(A.C2) C2
FROM T100 A,
(SELECT ROWNUM NO
FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)
) X,
(SELECT ROWNUM NO FROM USER_TABLES) Y
WHERE Y.NO <= X.CNT
결과가 아래와 같이 나온다.
GRP_UNIT C1 C2
---------- ------ ----------
1 A 10
2 B 20
3 C 30
4 D 40
5 E 50
1 150
2 150
3 150
4 150
5 150
이제 GRP_UNIT을 GROUPING 단위로 해서 그룹만 지어지면
원하는 결과를 얻을 수 있다.
이때 C1,C2 에는 MIN 또는 MAX 함수를 적용하며 백분율은
그 두 값을 이용해 계산하고 ROUND 처리를 해준다.
최종문장은 아래와 같이 된다.
SELECT MIN(X.C1) C1,
MIN(X.C2) C2,
ROUND(MIN(C2) / MAX(C2) * 100, 2) C2_RT
FROM (SELECT COUNT(B.NO) CNT,
MIN(DECODE(B.NO, 1, A.C1)) C1,
SUM(A.C2) C2
FROM T100 A,
(SELECT ROWNUM NO
FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)
) X,
(SELECT ROWNUM NO FROM USER_TABLES) Y
WHERE Y.NO <= X.CNT
GROUP BY
DECODE(X.CNT, 1, ROWNUM,Y.NO)
뒷풀이.
한번 더 강조하지만 백분율을 구해야할 대상 DATA 가 많아지면
INDEX가 있는 복제 전용 TABLE을 사용하는 것이 필수적이다.
약 만건만 되어도 INDEX 없는 복제는 10분 단위를 넘어서야
결과가 나온다.
T100 에 다음과 같은 DATA가 들어있다.
C1 C2
------ ----------
A 10
B 20
C 30
D 40
E 50
문제.
T100 TABLE의 ACCESS 가 한번만 허용된 상태라고 할때
- 실제로 ACCESS가 한번만 허용될리는 없다.
단지 조건이 복잡하다거나
INDEX가 존재하지 않는다거나 하는 여러가지 이유로 두번 읽는것이
부담스러울 경우가 있다. -
MAIN TABLE인 T100 을 한번만 읽은 후 가공을 통하여 백분율을
구해내는 문제다.
결과 가 다음처럼 나오면 된다.
C1 C2 C2_RT
------ ---------- ----------
A 10 6.67
B 20 13.33
C 30 20
D 40 26.67
E 50 33.33
대부분의 경우는 오히려 이문제에서 요구하는 답보다
차라리 TABLE을 한번 더 ACCESS 하여 미리 합을 구해놓고 그 값을
이용해 백분율을 구하는 방법이 쓰기 간편하고 효과도 뛰어나다.
생각.
이 문제를 주어진 환경 안에서 해결하기 위해 가장먼저 고려 되어야
할 것은 이제까지 우리가 이용했던 복제이다.
복제를 하기위해 여태까지 우리는 복제용 테이블을 이용하지 않았다.
그 이유는 여태까지 우리가 다루었던 주제에서는 주어진 DATA의
샘플이 그 원리 만을 설명하기에 충분할 만큼만 주어졌기 때문이다.
하지만 DATA가 매우 많아져서 많은 양의 복제가 일어나야 한다면
- 그런 경우도 그리 흔하지 않지만
이번 예제가 그런 경우가 될 수 있다 -
복제를 하기위해 많은 ROW수를 가진 TABLE에서 ROWNUM을 읽어오는
방식 보다는 INDEX가 생성되어 있는 복제전용 테이블을 이용하는
것이 효율적일 수 있다.
다시 문제를 해결하기 위한 방법으로 돌아와서 생각하자.
복제가 어떻게 이용될 것인가는 차차 얘기하고 가장 급선무는 역시
읽어 온 DATA의 전체 합계를 알아야 백분율을 구할 수 있다는 얘기다.
전체합계 역시 복제를 이용해 구한다.
전체 합계를 구하는 문제는 여러번 접해 봤기에 더 이상
설명하지 않겠다.
전체합계를 구한 후 그 값을 전체 ROW 수 만큼 복제하여 각
ROW 마다 하나씩 MATCH 시켜주는 단계를 밟는다.
이때 백율율 계산 대상이 되는 전체 ROW수도 필요하다는 것을
알 수 있다.
그래야지만 그 수만큼 복제를 할 수 있기 때문이다.
그리고 각 ROW와 그 ROW에 연결될 합계 값을 MATCH 시켜줄 GROUPING
조건을 찾는 것이 문제를 해결하는 가장 중요한 열쇠다.
그렇게 하고 나면 애초 DATA의 값과 합계값을 이용해 백분율을 구하는
것은 산수다.
해법.
항상 말로는 설명이 어렵다.
직접 예제를 통해 알아보자.
단계1.위에서 언급 되었듯이 첫 단계에서 필요한 정보요소를
나열하면
다음과 같다.
C1 : KEY 역할을 하므로 언제나 필요한 정보다.
C2 : 백분율을 구할때 분자가 된다
합계 : 백분율을 구할때 분모가 된다
ROW수 : 합계를 ROW수 만큼 복제하는 단계에서 유용하게
쓰일 정보다.
한가지 염두에 둘 것은 이번 단계에서 합계가 나오긴 하지만
그 합계가 하나의 ROW값으로 나온다는 것이다.
뒤에 그 하나의 ROW를 복제하여 각각의 ROW와 연결 지어 줄
것이다.
SELECT COUNT(B.NO) CNT, <- ROW수
MIN(DECODE(B.NO, 1, A.C1)) C1, <- C1(합계는 C1에 NULL)
SUM(A.C2) C2 <- C2(합계)
FROM T100 A,
(SELECT ROWNUM NO FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)
CNT C1 C2
---------- ------ ----------
1 A 10
1 B 20
1 C 30
1 D 40
1 E 50
5 150
위의 문장은 바로위와 같은 결과를 RETURN 한다.
여기서 마지막 ROW가 합계를 가지고 있는 ROW이며,
원래 DATA의 ROW수에 대한 정보도 가지고 있는 RECORD 이다.
단계2.위의 상태에서 CNT에 나타난 숫자 만큼만 각 ROW를 복제한다.
합계정보를 가지고 있는 마지막 ROW만 5번 복제가 되어 나오며
나머지는 한번의 복제가 일어나므로 결국 자신의 값을 그대로
가지게 된다.
이단계가 바로 다량의 복제를 일으킬 수 있는 부분이다.
현재는 ROW수가 5개밖에 없어서 5번의 복제가 일어나지만,
건수가 많아진다면,INDEX가 걸린 복제전용 TABLE을 쓰느냐
그렇지않고 ROW가 그보다 많은 TABLE에서 ROWNUM을
채취하여 쓰느냐 에 따라 엄청난 속도의 차이를 가져온다.
현재의 문제에서는 DATA 가 몇건 안되므로 ROWNUM을 채취하여
사용 하겠다.
복제를 한 후 다음과 같은 정보를 보자.
NO : 복제번호
ROWNUM : 복제후의 ROWNUM
CNT : 합계를 구할때의 CNT
C1,C2
SELECT NO,ROWNUM,CNT,C1,C2
FROM (SELECT COUNT(B.NO) CNT,
MIN(DECODE(B.NO, 1, A.C1)) C1,
SUM(A.C2) C2
FROM T100 A,
(SELECT ROWNUM NO
FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)) X,
(SELECT ROWNUM NO FROM USER_TABLES) Y
WHERE Y.NO <= X.CNT
NO ROWNUM CNT C1 C2
---------- ---------- ---------- ------ ----------
1 1 1 A 10
1 2 1 B 20
1 3 1 C 30
1 4 1 D 40
1 5 1 E 50
1 6 5 150
2 7 5 150
3 8 5 150
4 9 5 150
5 10 5 150
위의 결과를 살펴보면 원 DATA의 ROW수 와 합계값을 가진
ROW수가 서로 같다는 것을 알 수 있다.
그렇다면 DATA 하나에 합계를 하나씩 연결해주는 작업을 해보자.
다음 단계는 두개(각 DATA와 합계)에 같은 GROUP 단위를
주어주고 GROUP BY 하는 것이다.
먼저 연결을 위한 동일 GROUP 단위 부여를 위해 위의 결과를
자세히 살펴보자.
모든 RECORD는 ROWNUM이 1부터 차례로 주어져 있다.
그리고 합계는 NO가 1부터 다시 주어져 있다.
한가지 문제가 된다면 합계값을 가지는 ROW들이 1부터 다시
시작되지만,
합계가 아닌 원 DATA의 NO 값은 모두 1이라는 것이다.
즉,첫번째 합계를 나타내는 NO 1 이 원DATA의 NO 1과 구분이
되어져야 한다는 것이다.
하지만 그것도 그리 큰 문제점은 아니다.
CNT 가 가진 정보를 보면 그 ROW가 원래 DATA인지 아니면
합계용 DATA 인지를 쉽계 구분할 수 있기 때문이다.
단계3.최종적으로 보여야 될 정보는 C1,C2,그리고
DATA/(DATA의 ROWNUM과 같은 NO를 가진 합계)*100 이다.
DATA 와 (DATA의 ROWNUM과 같은 NO를 가진 합계) 를
하나의 ROW로 묶기위해 GROUP BY할 단위는 이미 정해졌다.
CNT 가 1이면 ROWNUM을 아니면 NO 를 GROUPING 단위로
주어주면 같은 GROUPING 단위를 갖는 ROW가 DATA 1개 ,
합계 1개 씩
총 두개씩이 생긴다.
QUERY를 다시 다음과 같이 바꿔보자.
SELECT DECODE(X.CNT, 1, ROWNUM,Y.NO) GRP_UNIT,
C1,
C2
FROM (SELECT COUNT(B.NO) CNT,
MIN(DECODE(B.NO, 1, A.C1)) C1,
SUM(A.C2) C2
FROM T100 A,
(SELECT ROWNUM NO
FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)
) X,
(SELECT ROWNUM NO FROM USER_TABLES) Y
WHERE Y.NO <= X.CNT
결과가 아래와 같이 나온다.
GRP_UNIT C1 C2
---------- ------ ----------
1 A 10
2 B 20
3 C 30
4 D 40
5 E 50
1 150
2 150
3 150
4 150
5 150
이제 GRP_UNIT을 GROUPING 단위로 해서 그룹만 지어지면
원하는 결과를 얻을 수 있다.
이때 C1,C2 에는 MIN 또는 MAX 함수를 적용하며 백분율은
그 두 값을 이용해 계산하고 ROUND 처리를 해준다.
최종문장은 아래와 같이 된다.
SELECT MIN(X.C1) C1,
MIN(X.C2) C2,
ROUND(MIN(C2) / MAX(C2) * 100, 2) C2_RT
FROM (SELECT COUNT(B.NO) CNT,
MIN(DECODE(B.NO, 1, A.C1)) C1,
SUM(A.C2) C2
FROM T100 A,
(SELECT ROWNUM NO
FROM USER_TABLES WHERE ROWNUM < 3) B
WHERE B.NO <= 2
GROUP BY
DECODE(B.NO, 1, A.C1)
) X,
(SELECT ROWNUM NO FROM USER_TABLES) Y
WHERE Y.NO <= X.CNT
GROUP BY
DECODE(X.CNT, 1, ROWNUM,Y.NO)
뒷풀이.
한번 더 강조하지만 백분율을 구해야할 대상 DATA 가 많아지면
INDEX가 있는 복제 전용 TABLE을 사용하는 것이 필수적이다.
약 만건만 되어도 INDEX 없는 복제는 10분 단위를 넘어서야
결과가 나온다.
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
34 | 반올림 DATA의 오차보정 | 운영자 | 2002.09.18 | 3583 |
33 | 복제를이용한 합계계에서 비율계산 | 운영자 | 2002.09.18 | 3669 |
32 | DATA변환 | 운영자 | 2002.09.18 | 2750 |
31 | 중간값구하기 | 운영자 | 2002.09.18 | 3377 |
» | 한번 읽은 테이블로 백분율 구하기 | 운영자 | 2002.09.18 | 4085 |
29 | 빠진이빨찾기 III | 운영자 | 2002.09.18 | 3359 |
28 | 빠진이빨찾기 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 |