안녕하세요 종종 들어와서 쿼리공부를 하고 있습니다.
실력부족으로 도움이 필요하여 글을 남기게 되었습니다.
WITH TEMP AS (
SELECT 10 AS LINE_NUM
,100 AS VAL
,20 AS LINE0
,NULL AS LINE1
,NULL AS LINE2
,NULL AS LINE3
,NULL AS LINE4
FROM DUAL
UNION ALL
SELECT 20 AS LINE_NUM
,200 AS VAL
,NULL AS LINE0
,30 AS LINE1
,40 AS LINE2
,50 AS LINE3
,60 AS LINE4
FROM DUAL
UNION ALL
SELECT 30 AS LINE_NUM
,300 AS VAL
,NULL AS LINE0
,NULL AS LINE1
,NULL AS LINE2
,NULL AS LINE3
,NULL AS LINE4
FROM DUAL
UNION ALL
SELECT 40 AS LINE_NUM
,400 AS VAL
,NULL AS LINE0
,NULL AS LINE1
,NULL AS LINE2
,NULL AS LINE3
,NULL AS LINE4
FROM DUAL
UNION ALL
SELECT 50 AS LINE_NUM
,500 AS VAL
,NULL AS LINE0
,NULL AS LINE1
,NULL AS LINE2
,NULL AS LINE3
,NULL AS LINE4
FROM DUAL
UNION ALL
SELECT 60 AS LINE_NUM
,600 AS VAL
,NULL AS LINE0
,NULL AS LINE1
,NULL AS LINE2
,NULL AS LINE3
,NULL AS LINE4
FROM DUAL
)
SELECT *
FROM TEMP
WHERE 1 = 1;
위와같은 데이터가 있습니다.
나와야 하는 결과값이
LINE_NUM VAL
10 2100
20 2000
30 300
40 400
50 500
60 600
컬럼설명을 드리면 VAL컬럼은 각라인의 값을 뜻하고,
LINE0~4 는 각 LINE_NUM의 값을 뜻합니다.
예로 라인10의 값을 구하려면,
라인10의 VAL값 100 + LINE0 의 라인20의 값을 가져오는 것입니다.
그런데 라인20의 200만 가져오는 것이 아니라 라인20의 LINE1~4 까지의
값까지 가져와야 합니다.
2번행의 쿼리를 잘못 작성하였습니다.
SELECT 20 AS LINE_NUM
,200 AS VAL
,30 AS LINE0
,40 AS LINE1
,50 AS LINE2
,60 AS LINE3
,NULL AS LINE4
FROM DUAL
이렇게 되어야 합니다...
===============================================
안녕하세요.
계산식은 각행별로 VAL + LINE0 + LINE1 + LINE2 + LINE3 + LINE4 으로 되어야 합니다.
이때, LINE0~4 의 값은 LINE_NUM 의 값으로 LINE_NUM 에 해당하는 VAL 값을 가져와야 합니다.
EX) 2행의 경우, 해당행의 VAL(200) + LINE0(행번호 30=> VAL 300) + LINE0(행번호 40=> VAL 400) + LINE0(행번호 50=> VAL 500) + LINE0(행번호 60=> VAL 600) = 2000 의 값이 나와야 합니다.
추가로 질문하나 더 여쭈어 봅니다...
WITH TEMP AS (
SELECT 10 AS LINE_NUM
,100 AS VAL
,20 AS LINE0
,'A' AS CAL00
,NULL AS LINE1
,NULL AS CAL01
,NULL AS LINE2
,NULL AS CAL02
,NULL AS LINE3
,NULL AS CAL03
,NULL AS LINE4
,NULL AS CAL04
FROM DUAL
UNION ALL
SELECT 20 AS LINE_NUM
,200 AS VAL
,30 AS LINE0
,'A' AS CAL00
,40 AS LINE1
,'A' AS CAL01
,50 AS LINE2
,'A' AS CAL02
,60 AS LINE3
,'S' AS CAL03
,NULL AS LINE4
,NULL AS CAL04
FROM DUAL
UNION ALL
SELECT 30 AS LINE_NUM
,300 AS VAL
,NULL AS LINE0
,NULL AS CAL00
,NULL AS LINE1
,NULL AS CAL01
,NULL AS LINE2
,NULL AS CAL02
,NULL AS LINE3
,NULL AS CAL03
,NULL AS LINE4
,NULL AS CAL04
FROM DUAL
UNION ALL
SELECT 40 AS LINE_NUM
,400 AS VAL
,NULL AS LINE0
,NULL AS CAL00
,NULL AS LINE1
,NULL AS CAL01
,NULL AS LINE2
,NULL AS CAL02
,NULL AS LINE3
,NULL AS CAL03
,NULL AS LINE4
,NULL AS CAL04
FROM DUAL
UNION ALL
SELECT 50 AS LINE_NUM
,500 AS VAL
,NULL AS LINE0
,NULL AS CAL00
,NULL AS LINE1
,NULL AS CAL01
,NULL AS LINE2
,NULL AS CAL02
,NULL AS LINE3
,NULL AS CAL03
,NULL AS LINE4
,NULL AS CAL04
FROM DUAL
UNION ALL
SELECT 60 AS LINE_NUM
,600 AS VAL
,NULL AS LINE0
,NULL AS CAL00
,NULL AS LINE1
,NULL AS CAL01
,NULL AS LINE2
,NULL AS CAL02
,NULL AS LINE3
,NULL AS CAL03
,NULL AS LINE4
,NULL AS CAL04
FROM DUAL
)
SELECT *
FROM TEMP A
================================
위와 같은 데이터가 있습니다.
각행별의 계산식입니다. VAL + (CAL00)LINE0 + (CAL01)LINE1 + (CAL02)LINE2 + (CAL03)LINE3 + (CAL04)LINE4
CAL00~04 컬럼은 'A'인경우 + 부호에 해당하고, 'S'인경우, - 부호입니다.
따라서, 2행을 예로 들면,
200 + (+)300[3행의 VAL] + (+)400[4행의 VAL] + (+)500[5행의 VAL] + (-)600[6행의 VAL] = 800
이런식으로
최종 결과값은
LINE_NUM VAL
10 900
20 800
30 300
40 400
50 500
60 600
이렇게 나와야 됩니다.
계층구조(부모-자식 관계) 형태로 자료를 변경한뒤
하위에서 상위로 부호를 적용하여 누적합계 구하는 방법을 사용했습니다.
제시하신 예제에선 마이너스 부호가 한번만 나와서
마이너스가 중첩되는 경우에 대한 예제로 바꿔봤습니다.
아래는 이와 관련된 SQL퀴즈입니다.
http://www.gurubee.net/lecture/2643
http://www.gurubee.net/article/46097
WITH temp (line_num, val, line0, cal00, line1, cal01, line2, cal02, line3, cal03, line4, cal04) AS ( SELECT 10, 100, 20, 'A', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dual UNION ALL SELECT 20, 200, 30, 'A', 40, 'A', 50, 'A', 60, 'S', NULL, NULL FROM dual UNION ALL SELECT 30, 300, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dual UNION ALL SELECT 40, 400, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dual UNION ALL SELECT 50, 500, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dual UNION ALL --SELECT 60, 600, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dual UNION ALL SELECT 60, 600, 70, 'S', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dual UNION ALL SELECT 70, 700, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL FROM dual ) , tmp AS ( SELECT c, p, s, b.val v FROM (SELECT DECODE(lv, -1, NULL, line_num) p , DECODE(lv, -1, line_num , 0, line0, 1, line1, 2, line2, 3, line3, 4, line4) c , DECODE(lv, -1, 'A' , 0, cal00, 1, cal01, 2, cal02, 3, cal03, 4, cal04) s FROM temp , (SELECT LEVEL-2 lv FROM dual CONNECT BY LEVEL <= 6) ) a , temp b WHERE a.c = b.line_num ) SELECT line_num , SUM(v * s) v FROM (SELECT CONNECT_BY_ROOT(c) line_num , DECODE( MOD(LENGTH(REPLACE(SYS_CONNECT_BY_PATH(s, ','), 'S')), 2) , 0, 1, -1) s , v , c, p FROM tmp START WITH p IS NULL CONNECT BY PRIOR c = p ) GROUP BY line_num ORDER BY line_num ;
SELECT TT, SUM(VAL)
FROM ( SELECT CONNECT_BY_ROOT(LINE_NUM) AS TT,
VAL * DECODE(DECODE(LINE_NUM, PRIOR LINE0, PRIOR CAL00, PRIOR LINE1, PRIOR CAL01, PRIOR LINE2, PRIOR CAL02, PRIOR LINE3, PRIOR CAL03), 'S', -1, 1) AS VAL
FROM TEMP A
CONNECT BY LINE_NUM IN ( PRIOR LINE0, PRIOR LINE1, PRIOR LINE2, PRIOR LINE3, PRIOR LINE4))
GROUP BY TT
ORDER BY TT;
마이너스 부호가 이중으로 적용되는 경우까지 고려한다면?
아래와 같이 해야 할 듯 합니다.
위에 제가 예를 든 자료를 보면
60 은 600 - 700 = -100 이 됩니다.
20 에서 60을 참조할 때 위 결과 -100 에 - 를 적용하여 -(-100) = 100 을 가져와야 합니다.
이중 마이너스에 대한 처리를 하지 않으면
- 600 - 700 = - 1300 을 가져오게 됩니다.
SELECT line_num , SUM(val * s) val FROM (SELECT CONNECT_BY_ROOT(line_num) AS line_num , val , DECODE(MOD(LENGTH(REPLACE( SYS_CONNECT_BY_PATH(DECODE(line_num, PRIOR line0, PRIOR cal00 , PRIOR line1, PRIOR cal01 , PRIOR line2, PRIOR cal02 , PRIOR line3, PRIOR cal03 , PRIOR line4, PRIOR cal04 , 'A'), ',') , 'S')), 2), 0, 1, -1) s FROM temp CONNECT BY line_num IN ( PRIOR line0 , PRIOR line1 , PRIOR line2 , PRIOR line3 , PRIOR line4 ) ) GROUP BY line_num ORDER BY line_num ;