복잡한 현실의 업무를 처리하다 보면 데이터 모델상으로는 서로 다르지만 몇 가지 서로 상이한 부분만 보정하면 통일된 방식으로 처리할 수 있는 경우가 많이 나타난다.
복잡하고 변화 무쌍한 것들을 단순 - 명확하게 해결할 수 있는것이 바로 실력이라 생각한다.
이 데이터 모델은 서로 닮아 있는 부분이 많다. - 색깔별로 표시한 것.
이 모델을 토대로 몇가지 사례를 모아보자
구분 | 상환 | 예입 | |
---|---|---|---|
일자 | 상환일자 | 예입일자 | |
종류 | 차입종류 | 예금종류 | |
은행 | 차입처 | 예입처 | |
개시일 | 약정일자 | 개설일자 | |
만기일 | 만기일 | 만기일 | |
금액 | 원금상환원화+원화이자 | 원화금액 | =>'일별환율'테이블에서 적용환율을 찾아 원화로 환산 |
손익부문 | 손익부문 | 손익부문 | =>예적금인경우 '부서'테이블경유 |
화면
해당 SQL
SELECT w.구분 as 구분
,to_char(to_date(w.일자,'yyyymmdd'),'mm/dd') as 일자 -- 메인쿼리에서 가공함
,y.계정과목명 as 종류
,x.은행명 as 은행명
,w.개시일 as 개시일
,w.만기일 as 만기일
,w.원화금액 as 금액
,z.부문명 as 손익부문
FROM (
SELECT '상환' as 구분
,b.상환일자 as 일자 -- 상환일자
,a.차입종류 as 종류코드
,a.차입처 as 거래처코드
,a.개설일자 as 개시일
,a.만기일
,b.원금상환원화 + b.원화이자 + (b.원금상환외화+b.외화이자)*c.환율 as 원화금액
,b.부문코드
FROM 차입금원장 a, 상환내역 b, 일별환율 c
WHERE a.관리번호 = b.관리번호
AND c.환율일자 = b.상환일자
AND c.환율종류 = 'TTB'
UNION ALL
SELECT '예금' as 구분
,b.매입일자 as 일자 --예입일자
,a.예금종류 as 종류코드
,a.예입처 as 거래처코드
,a.만기일
,b.원화금액
,b.부문코드
FROM 예적금원장 a, 예입내역 b, 부서 c
WHERE b.관리번호 = a.관리번호
AND c.부서코드 = a.예입부서
) w, 거래처 x, 계정과목 y, 손익부문 z
WHERE x.거래처코드 = w.거래처코드
AND y.계정과목 = w.종류코드||'00'
AND z.부문코드 = w.부문코드
AND w.일자 between '980305' and '980310'
서로 상이하거나 조인해야 할 대상이 서로다른 경우
h2.9.2.UNION을 사용한 인라인뷰의 주의사항
SELECT COL3, SUM(RESULT1), SUM(RESULT2)
FROM (
SELECT COL3, SUM(QTY) AS RESULT1, 0 AS RESULT2
FROM TAB1
WHERE DAT1 BETWEEN :VAL1 AND :VAL2
AND COL2 IN ('1','2')
GROUP BY COL3
UNION
SELECT COL3, 0 AS RESULT1, SUM(QTY) AS RESULT2
FROM TAB1
WHERE DAT1 BETWEEN :VAL1 AND :VAL2
AND COL2 = '5'
AND COL4 = 'A'
GROUP BY COL3
)
WHERE others_conditions......
GROUP BY COL3 ;
1. 불필요하게 'UNION' 사용.
SELECT COL3
,SUM(DECODE(COL2,'5',NULL,QTY) AS RESULT1
,SUM(DECODE(COL2||COL4,'5A',QTY)) AS RESULT2
FROM TAB1
WHERE DAT1 BETWEEN :VAL1 AND :VAL2
AND COL2 IN ('1','2','5')
GROUP BY COL3
HAVING others_conditions......
SELECT COL3
,SUM(DECODE(COL2,'5',NULL,QTY) AS RESULT1
,SUM(DECODE(COL2||COL4,'5A',QTY)) AS RESULT2
FROM TAB1
WHERE DAT1 IN (SELECT YMD||''
FROM YMD_DUAL -- 일자만 문자타입으로 가지고 있는 보조테이블
WHERE YMD BETWEEN :VAL1 AND :VAL2) -- '점'을 '선'으로 만들어줌
AND COL2 IN ('1','2','5')
GROUP BY COL3
HAVING others_conditions......
SELECT COL3
,SUM(DECODE(COL2,'5',NULL,QTY) AS RESULT1
,SUM(DECODE(COL2||COL4,'5A',QTY)) AS RESULT2
FROM TAB1
WHERE (DAT1, COL2) IN (SELECT YMD, TO_CHAR(NO)
FROM YMD_DUAL X, COPY_T Y
WHERE X.YMD BETWEEN :VAL1 AND :VAL2
AND Y.NO IN (1,2,5))
GROUP BY COL3
HAVING others_conditions......
2. UNION 사용 -> 'UNION ALL' 사용
3. 불필요하게 GROUP BY가 더 수행됨.
SELECT CUST_CD, SUM(QTY)
FROM (
SELECT CUST_CD, QTY
FROM TAB1
WHERE DAT1 BETWEEN :VAL1 AND :VAL2
AND COL2 = '1'
UNION
SELECT Y.BYSINESS_NO AS CUST_CD, X.QTY
FROM TAB1 X, TAB2 Y
WHERE X.KEY = Y.KEY
AND X.DAT1 BETWEEN :VAL1 AND :VAL2
AND COL2 = '2'
)
WHERE others_conditions......
GROUP BY CUST_CD ;
위 쿼리 실행시 인덱스 구조에 따른 효율성 문제.
인덱스 구조가 문제없는 경우 | 인덱스 구조가 문제있는 경우 |
---|---|
중복 엑세스 없음 | 중복 엑세스 |
'COL2+DAT1' 일경우 문제없음, 'DAT1+COL2' 일경우 DAT1의 BETWEEN -> IN 변경 | DAT1 로만 되어있는경우, DAT1이 COL2가 아닌 다른 컬럼과 결합되어 있는경우 |
인덱스 구조가 문제있는 경우 처리방안
SELECT DECODE(X.COL1, '1', CUST_CD, Y.BYSINESS_NO) AS CUST_NO, SUM(QTY)
FROM TAB1 X, TAB2 Y
WHERE (X.COL2 = '1' OR X.COL2 = '2' AND X.KEY = Y.KEY)
AND X.DAT1 BETWEEN :VAL1 AND :VAL2
AND others_conditions......
GROUP BY DECODE(X.COL1, '1', CUST_CD, Y.BYSINESS_NO);
SELECT NVL(Y.BYSINESS_NO,X.COL1) AS CUST_NO, SUM(QTY)
FROM TAB1 X, TAB2 Y
WHERE Y.KEY1(+) = DECODE(X.COL2,'2',X.KEY1) -- COL2가 '1'이면 NULL로, '2'면 COL2로 조인
AND X.DAT1 BETWEEN :VAL1 AND :VAL2
AND others_conditions......
GROUP BY NVL(Y.BYSINESS_NO,X.COL1);