by-nc-sa     개발자, DBA가 함께 만들어가는 구루비 지식창고!

1. 조인을 활용한 데이터 연결




1. 조인을 활용한 데이터 연결

-조인은 관련된 다른 집합을 찾아오는 것이 아니다.
-EQUAL(=)로만 조인하는 것이 아니다.


-조인은 집합간의 곱이다.
-모든 연산자가 연결조건이 될 수 있다.

1 * M = M
M * 1 = M
1 * 1 = 1
M * M = MM

-항상 조인에 =을 사용하는 것은 아니다. 활용법에 따라 between을 쓸 수도, like를 쓸 수도 있다

1.1 카테시안(Cartesian)곱을 이용한 조인

1.1.1 나열된 컬럼을 여러 레코드로 생성

CREATE table copy_t (NO, NO2) as 
SELECT rownum, 
                 substr(to_char(rownum,'09'),2,2)
FROM    any_table
WHERE rownum <= 31 ;

INSERT into 전표테이블 
              (생성일자, ... , 계정과목, 금액, ... )
SELECT to_char(sysdate,'yyyymmdd'), ... , 
                 decode(y.no, 1, '1234', 
                                       2, '5678', 
                                       3,'9876'),
                 decode(y.no, 1, 반환금, 
                                       2, 위약금, 
                                       3, 기기철거비), ...
FROM  계약정산테이블 x, COPY_T y
WHERE  x.해약일 = :input_date
         and  y.NO <= 3 ;

COPY_T 테이블을 이용하여 금액이 있는 컬럼 만큼 로우를 복제한 후 각 로우마다 
필요한 값을 지정하여 INSERT


INSERT  into 전표테이블
                (생성일자, ... , 계정과목, 금액, ... )
SELECT  to_char(sysdate,'yyyymmdd'), ... , 
                  decode(y.no, 1, '1234',
                                        2, '5678', 
                                        3, '9876'),
                  decode(y.no, 1, 반환금, 
                                        2, 위약금,
                                        3, 철거비), ...
FROM    계약정산테이블 x,  COPY_T y
WHERE x.해약일 = :input_date
        and  y.NO in (decode(반환금,0,null,1),       
                                decode(위약금,0,null,2),
                                decode(철거비,0,null,3)) ;

COPY_T 테이블을 이용하여 복제할 때 복제원 로우의 값에 따라 복제할 양을 유동적으로 결정

1.1.2 첨자 LOOP형 처리

선급금

순번 발생일 시작일 종료일 선급금액
1101 970501 970520 970925 5,000,000
1102 970601 970615 970805 3,800,000
1103 970701 970712 971020 6,780,000
1104 970501 970507 970718 2,890,000

월별매출

순번 적용월 매출금액 .....
1101 9705 429,687 .....
1101 9706 1,171,875 .....
1101 9707 1,210,937 .....
1101 9708 1,210,937 .....
1101 9709 976,564 .....
INSERT  into 월별매출
               (일련번호, 적용월, 매출금액, ... )
SELECT 일련번호, substr(:작업월,1,4)||y.NO2,
                (decode(y.NO2, to_char(종료일,'mm'),
                                           to_char(종료일,'dd'),
  to_char(last_day(to_date(substr(:작업월,1,4)
              ||y.NO2),'yyyymm')),'dd')) 
    -             decode(y.NO2, to_char(시작일,'mm'),
                                            to_char(시작일,'dd'),'01')
                  +1) *  (선급액/(종료일-시작일)+1)), ...
FROM   선급금 x,  COPY_T y    
WHERE x.발생일 like :작업월||'%' 
        and  y.NO2 between to_char(시작일,'mm')
                             and        to_char(종료일,'mm') ; 

-COPY_T 테이블을 이용하여 필요한 개수만큼 로우를 복제함으로써 마치 각 로우마다 n번의 Loop가 수행되는 것처럼 사용

1.2 관계가 없는 테이블간의 조인

-1* 1 * 1 = 1 이므로 각각의 테이블이 기본키로 액세스된다면 하나의 SQL로 JOIN 가능,

SELECT 고객명, 부서, 호봉, 편성금액, 
        into  :cust_name, :dept, :salgrade, 
                :budget_amt,  
FROM   CUSTOMER, 
               EMPLOYEE, 
               BUDGET
WHERE고객번호  = :cust_no 
        and 사번      = :emp_no
        and 부서(+) = :dept_no || SUBSTR(사번,0,0)
        and 계정과목(+) = '1101'
        and 예산년도(+) = to_char(sysdate,'yyyy') ;

-관계가 없는 테이블간의 join을 하면 catesian 곱만큼의 로우가 생성되지만, 1 * 1은 항상 1밖에 안된다.
주의할 점은 조인은 어느 한 집합만 공집합이 되더라도 전체 집합이 공집합이 되기 때문에, 그럴 가능성이 있는 컬럼을 제외시키거나 outer join을 해야한다.

1.3 처리결과를 고정된 양식에 맞추는 조인

SELECT  y.계정명,
           sum(decode(x.부문,'원사',금액)), 
           sum(decode(x.부문,'제직',금액)), 
            .............................................  
FROM (SELECT substr(계정,1,2) 항목,
                            sum(금액) 금액
             FROM  전표테이블
             WHERE 공장코드 = '1공장'
                    and 일자 like :작업월||'%'
                    and 계정 between '1234' 
                                   and          '6543'
             GROUP BY substr(계정,1,2) ) x,
             계정테이블 y 
WHERE y.계정 between '1200' and '6500'
       and y.분류 = '1' 
       and x.항목(+) = substr(y.계정,1,2) ;

-처리결과가 없으면 빈칸이 아니라 0이 나오도록 하는 것이 보기 좋다.앞서 말한 outer 조인을 사용하면 된다
-GROUP BY한 결과가 없는 항목도 추출되도록 모든 추출항목이 있는 집합과 OUTER 조인 (Sort_Merge나 Hash 조인으로 수행시킬것)

1.4 조인을 이용한 소계처리

SELECT  item, 
                decode(NO,1,grade,'소계'),
                sum(m_qty), sum(m_amt), 
                sum(s_qty),  sum(s_amt)
FROM ( SELECT item, grade,
                             sum(m_qty)   m_qty, 
                             sum(m_amt)  m_amt,
                             sum(s_qty)    s_qty,   
                             sum(s_amt)   s_amt
              FROM   TAB1
              WHERE yymm  = :in_daye
                    and  saup    = :saup 
              GROUP BY item, grade ) x, 
              COPY_T y
WHERE y.NO <= 2 
GROUP BY item, 
         NO, 
         decode(NO,1,grade,'소계') ;

DECODE(NO,1,'소계', GRADE) 로 바꾸면 소계가 먼저 오고, 그 아래에 내역이 오는 형식으로 
출력할 수가 있다. 

-New Feature : Rollup , Cube활용
-subquery에서 group by를 item, grade로 한 후에 NO의 값에 따라서 1일 때는 원래의 집합이 그대로, 2일 때는 소계로 group by 된다.
이 방법은 한번 엑세스하여 group by하면 처리 범위가 현격하게 줄어들게 된다.

참고자료

문서에 대하여

  • 최초작성자 : [VLDB:장세정]
  • 최초작성일 : 2007년 11월 27일
  • 이 문서는 오라클클럽 [대용량 데이터베이스 스터디] 모임에서 작성하였습니다.
  • 이 문서의 내용은 이화식님의 대용량 데이터베이스 솔루션2 을 참고했습니다.

문서정보

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.