누계를 구하는 또한가지 방법
조건.
TABLE A_TB 에 다음과 같은 DATA가 있다.
A_MON A_OUT
------ ----------
199801 1900000
199802 2000000
199803 1500000
199804 1100000
199805 2100000
199806 1600000
199807 1400000
199808 1700000
199809 1900000
199810 1000000
월별 집계 TABLE이다.
현재월은 1998년 10월로 10월 현재일까지의 집계금액이 존재하고있다.
입력 PARAMETER로서 :IN_MON이 있으며 년월을 가지는 6자리 VARCHAR2
타입이다.
문제.
현재월이 1998년 10월이므로 1998년 10월까지가 PARAMETER로 들어오면
해당년도의 1월부터 해당월까지 각월별로 누계값을 보여주고자 한다.
대신 현재월 이상의 값이 들어오면 잘못된 조건 입력으로 간주하여
RETURN되는 DATA가 한 건도 없도록 하고싶다.
참고로 :IN_MON PARAMETER 에 '199810' 이라는 값이 들어오면
다음과 같은 결과가 나올것이다.
월 실적
--------- ----------
199801 1900000
199802 3900000
199803 5400000
199804 6500000
199805 8600000
199806 10200000
199807 11600000
199808 13300000
199809 15200000
199810 17200000
생각.
엿보기1.PARAMETER 값에따라 몇건의 DATA를 읽을 것인가를 결정해야한다.
제일많이 읽어봐야 12개월치 일 것이다.
엿보기2.입력받은월과 현재월을 비교해서 입력월이 현재월보다 크면
RETURN되는 결과가 없도록하는 부분도 필요할 것이다.
엿보기3.먼저 입력년도의 1월부터 입력 해당월까지를 미리 RECORD로
준비해 놓고 1월DATA 부터 입력월까지의 DATA를 차례로 읽으면서
준비되어 기다리고 있는 월이 읽혀온 DATA를 포함하는 월보다
크면 그 값을 준비되어 있는 월에 더해주는 방식을 생각해보자.
해법.
누계 구하기에서 다루었던 방식과 일맥상통하는 방식이지만 새로운 맛을
느낄 수 있는 방식이기도 하다.
편의상 입력월을 '199810' 으로 가정하고 문제를 풀어보자.
단계1.우선 PARAMETER를 이용하여 해당년도를 떼어내고
입력된 월만큼의 RECORD의 ROWNUM을 차례로 뒤에 붙여주자
10개의 RECORD를 만들어주면된다.
다음과 같이 해보자.
SELECT SUBSTR(:IN_MON,1,4)||LPAD(TO_CHAR(ROWNUM),2,'0') V_MON
FROM A_TB
WHERE ROWNUM < 10 + 1
단계2.해당월이 10월이기 때문에
ROWNUM < 10 + 1
이라는 조건이 붙었다.
10을 입력 PARAMETER에 따라 바뀌도록 만들어보자.
10 + 1 대신 TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1
라고 써주면 된다.
단계3.만약에 해당월이 현재월보다 크면 ROWNUM < 1과 같이
되어야 한다.
IF :IN_MON >= TO_CHAR(SYSDATE,'YYYYMM') THEN
ROWNUM < 1
ELSE
ROWNUM < TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1
END IF;
와 같은 형식이다.
조건절에 그대로 옮겨보면 다음과 같이 된다.
WHERE ROWNUM
< DECODE(LEAST(:IN_MON,TO_CHAR(SYSDATE,'YYYYMM')),:IN_MON,
TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1,1)
단계4.이제 월별 실적을 읽어 오자.
다 읽을 필요는 없다.
해당년도의 1월부터 해당월까지만 필요하다.
그대로 표현해보자.
SELECT *
FROM A_TB
WHERE A_MON > SUBSTR(:IN_MON,1,4)
AND A_MON <= :IN_MON
단계5.위에서 만든 두개의 DATASET으로 CARTESIAN PRODUCT를 만들고
먼저만든 V_MON을 기준으로 SUM을 하되 V_MON 이 DATA의
월보다 클경우만 SUM에 포함시켜주자.
SELECT V_MON 월,
SUM(DECODE(LEAST(V_MON,A_MON),B.A_MON,
A_OUT)
) 실적
FROM 아까만든 DATASET 두개
WHERE 필요없고
GROUP BY
V_MON
단계6.최종 문장은 다음과 같다.
SELECT V_MON 월,
SUM(DECODE(LEAST(A.V_MON,B.A_MON),B.A_MON,
B.A_OUT)
) 실적
FROM (SELECT SUBSTR(:IN_MON,1,4)||
LPAD(TO_CHAR(ROWNUM),2,'0') V_MON
FROM A_TB
WHERE ROWNUM
< DECODE(LEAST(:IN_MON,TO_CHAR(SYSDATE,'YYYYMM')
),:IN_MON,
TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1,1)
) A,
(SELECT *
FROM A_TB
WHERE A_MON > SUBSTR(:IN_MON,1,4)
AND A_MON <= :IN_MON
) B
GROUP BY
A.V_MON
뒷풀이.
많은 부분에서 유용하게 사용되는 ROWNUM을 어떻게 CONTROL 하는가에
대한 좋은 예라고 할 수 있을 것이다.
열심히 이해하자.
열심히 안하고 대충 읽어만 봐도 무슨 짓을 하고 있구나 하고 알 수
있을 것이다.
이미 초보를 벗어났다는 증거다.
축하....
ROW 가 몇개 안되는 경우 이므로 부등호 조인을 이용하지 않고
사용했지만 부등호 JOIN을 통한 방법이 정석일 것이다.
그렇게 되면 단계5번에서 SELECT 부분이 바뀌며 WHERE부분이
추가 될것이다
SELECT V_MON 월,
SUM(A_OUT) 실적 -- 변경부분
WHERE B.A_MON <= A.V_MON -- 추가부분
조건.
TABLE A_TB 에 다음과 같은 DATA가 있다.
A_MON A_OUT
------ ----------
199801 1900000
199802 2000000
199803 1500000
199804 1100000
199805 2100000
199806 1600000
199807 1400000
199808 1700000
199809 1900000
199810 1000000
월별 집계 TABLE이다.
현재월은 1998년 10월로 10월 현재일까지의 집계금액이 존재하고있다.
입력 PARAMETER로서 :IN_MON이 있으며 년월을 가지는 6자리 VARCHAR2
타입이다.
문제.
현재월이 1998년 10월이므로 1998년 10월까지가 PARAMETER로 들어오면
해당년도의 1월부터 해당월까지 각월별로 누계값을 보여주고자 한다.
대신 현재월 이상의 값이 들어오면 잘못된 조건 입력으로 간주하여
RETURN되는 DATA가 한 건도 없도록 하고싶다.
참고로 :IN_MON PARAMETER 에 '199810' 이라는 값이 들어오면
다음과 같은 결과가 나올것이다.
월 실적
--------- ----------
199801 1900000
199802 3900000
199803 5400000
199804 6500000
199805 8600000
199806 10200000
199807 11600000
199808 13300000
199809 15200000
199810 17200000
생각.
엿보기1.PARAMETER 값에따라 몇건의 DATA를 읽을 것인가를 결정해야한다.
제일많이 읽어봐야 12개월치 일 것이다.
엿보기2.입력받은월과 현재월을 비교해서 입력월이 현재월보다 크면
RETURN되는 결과가 없도록하는 부분도 필요할 것이다.
엿보기3.먼저 입력년도의 1월부터 입력 해당월까지를 미리 RECORD로
준비해 놓고 1월DATA 부터 입력월까지의 DATA를 차례로 읽으면서
준비되어 기다리고 있는 월이 읽혀온 DATA를 포함하는 월보다
크면 그 값을 준비되어 있는 월에 더해주는 방식을 생각해보자.
해법.
누계 구하기에서 다루었던 방식과 일맥상통하는 방식이지만 새로운 맛을
느낄 수 있는 방식이기도 하다.
편의상 입력월을 '199810' 으로 가정하고 문제를 풀어보자.
단계1.우선 PARAMETER를 이용하여 해당년도를 떼어내고
입력된 월만큼의 RECORD의 ROWNUM을 차례로 뒤에 붙여주자
10개의 RECORD를 만들어주면된다.
다음과 같이 해보자.
SELECT SUBSTR(:IN_MON,1,4)||LPAD(TO_CHAR(ROWNUM),2,'0') V_MON
FROM A_TB
WHERE ROWNUM < 10 + 1
단계2.해당월이 10월이기 때문에
ROWNUM < 10 + 1
이라는 조건이 붙었다.
10을 입력 PARAMETER에 따라 바뀌도록 만들어보자.
10 + 1 대신 TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1
라고 써주면 된다.
단계3.만약에 해당월이 현재월보다 크면 ROWNUM < 1과 같이
되어야 한다.
IF :IN_MON >= TO_CHAR(SYSDATE,'YYYYMM') THEN
ROWNUM < 1
ELSE
ROWNUM < TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1
END IF;
와 같은 형식이다.
조건절에 그대로 옮겨보면 다음과 같이 된다.
WHERE ROWNUM
< DECODE(LEAST(:IN_MON,TO_CHAR(SYSDATE,'YYYYMM')),:IN_MON,
TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1,1)
단계4.이제 월별 실적을 읽어 오자.
다 읽을 필요는 없다.
해당년도의 1월부터 해당월까지만 필요하다.
그대로 표현해보자.
SELECT *
FROM A_TB
WHERE A_MON > SUBSTR(:IN_MON,1,4)
AND A_MON <= :IN_MON
단계5.위에서 만든 두개의 DATASET으로 CARTESIAN PRODUCT를 만들고
먼저만든 V_MON을 기준으로 SUM을 하되 V_MON 이 DATA의
월보다 클경우만 SUM에 포함시켜주자.
SELECT V_MON 월,
SUM(DECODE(LEAST(V_MON,A_MON),B.A_MON,
A_OUT)
) 실적
FROM 아까만든 DATASET 두개
WHERE 필요없고
GROUP BY
V_MON
단계6.최종 문장은 다음과 같다.
SELECT V_MON 월,
SUM(DECODE(LEAST(A.V_MON,B.A_MON),B.A_MON,
B.A_OUT)
) 실적
FROM (SELECT SUBSTR(:IN_MON,1,4)||
LPAD(TO_CHAR(ROWNUM),2,'0') V_MON
FROM A_TB
WHERE ROWNUM
< DECODE(LEAST(:IN_MON,TO_CHAR(SYSDATE,'YYYYMM')
),:IN_MON,
TO_NUMBER(SUBSTR(:IN_MON,5,2)) + 1,1)
) A,
(SELECT *
FROM A_TB
WHERE A_MON > SUBSTR(:IN_MON,1,4)
AND A_MON <= :IN_MON
) B
GROUP BY
A.V_MON
뒷풀이.
많은 부분에서 유용하게 사용되는 ROWNUM을 어떻게 CONTROL 하는가에
대한 좋은 예라고 할 수 있을 것이다.
열심히 이해하자.
열심히 안하고 대충 읽어만 봐도 무슨 짓을 하고 있구나 하고 알 수
있을 것이다.
이미 초보를 벗어났다는 증거다.
축하....
ROW 가 몇개 안되는 경우 이므로 부등호 조인을 이용하지 않고
사용했지만 부등호 JOIN을 통한 방법이 정석일 것이다.
그렇게 되면 단계5번에서 SELECT 부분이 바뀌며 WHERE부분이
추가 될것이다
SELECT V_MON 월,
SUM(A_OUT) 실적 -- 변경부분
WHERE B.A_MON <= A.V_MON -- 추가부분
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
54 | 소계/합계 함께 보기 | 운영자 | 2002.09.18 | 3134 |
53 | 석차구하기 | 운영자 | 2002.09.18 | 2960 |
52 | COLUMN을 ROW로 | 운영자 | 2002.09.18 | 6135 |
51 | 최대값과 최소값을 뺀 평균 | 운영자 | 2002.09.18 | 4177 |
» | 누계를 구하는 또한가지 방법 | 운영자 | 2002.09.18 | 3209 |
49 | 그룹 단위별 일련번호 붙이기 | 운영자 | 2002.09.18 | 5754 |
48 | 부등호 조인 | 운영자 | 2002.09.18 | 56705 |
47 | 행렬(matrix)계산을위한 준비 | 운영자 | 2002.09.18 | 3061 |
46 | 최대값과 해당해의 다른값 가져오기 | 운영자 | 2002.09.18 | 3221 |
45 | DATA 병합 | 운영자 | 2002.09.18 | 2578 |
44 | 다수 NULL 허용 COLUMN의 명칭을 가져올때 | 운영자 | 2002.09.18 | 3732 |
43 | 수식이용 | 운영자 | 2002.09.18 | 2738 |
42 | JOIN과 SUBQUERY가 동일한 예제 | 운영자 | 2002.09.18 | 2950 |
41 | NULL과 0 의 AVG 차이 비교 | 운영자 | 2002.09.18 | 2875 |
40 | 고정된 Row 수 유지 | 운영자 | 2002.09.18 | 4228 |
39 | 두개 RECORD를 한행에 DISPLAY 시키기 | 운영자 | 2002.09.18 | 3162 |
38 | LENGTH/LENGTHB,SUBSTR/SUBSTRB,INSTR/INSTRB | 운영자 | 2002.09.18 | 4292 |
37 | 한줄에 2 ROW 보여주기 변형II | 운영자 | 2002.09.18 | 3109 |
36 | 상호간 OUTER 조인의 해결방안 | 운영자 | 2002.09.18 | 2941 |
35 | 선택적조인 | 운영자 | 2002.09.18 | 2961 |