2014년 7월 14일 월요일

Standard Join

  제1절 표준 조인

1. Standard SQL 개요
1970년: Dr. E.F.Codd 관계형 DBMS(Relational DB) 논문 발표
1974년: IBM SQL 개발 1979년: Oracle 상용 DBMS 발표
1980년: Sybase SQL Server 발표 (이후 Sybase ASE로 개명)
1983년: IBM DB2 발표
1986년: ANSI/ISO SQL 표준 최초 제정 (SQL-86, SQL1)
1992년: ANSI/ISO SQL 표준 개정 (SQL-92, SQL2)    <=== Altibase
1993년: MS SQL Server 발표 (Windows OS, Sybase Code 활용)
1999년: ANSI/ISO SQL 표준 개정 (SQL-99, SQL3)
2003년: ANSI/ISO SQL 표준 개정 (SQL-2003)
2008년: ANSI/ISO SQL 표준 개정 (SQL-2008)

# 대표적인 ANSI/ISO 표준 SQL의 기능
- STANDARD JOIN 기능 추가 (CROSS, OUTER JOIN 등 새로운 FROM 절 JOIN 기능들)
- SCALAR SUBQUERY, TOP-N QUERY 등의 새로운 SUBQUERY 기능들
- ROLLUP, CUBE, GROUPING SETS 등의 새로운 리포팅 기능
- WINDOW FUNCTION 같은 새로운 개념의 분석 기능들

# E.F.Codd 박사의 논문에 언급된 8가지 관계형 대수(4개의 일반 집합 연산자와 4개의 순수 관계 연산자)

Seqno 분류 관계형 대수 SQL 설명
1 일반 집한 연산자 UNION UNION UNIONX은 정렬 작업 수행, UNION ALL 사용 권고
2 INTERSECTION INTERSECT 교집합
3 DIFFERENCE EXCEPT or MINUX(Oracle) 차집합
4 PRODUCT CROSS JOIN(Cartesian product) JOIN 조건이 없을 경우 M*N 데이터 조합 발생
Seqno 분류 관계형 대수 SQL 설명
5 순수 관계 연산자 SELECT WHERE 조건절  
6 PROJECT SELECT 절  
7 (NATURAL) JOIN JOIN WHERE절의 INNER JOIN 조건, FROM절의 NATURAL JON, INNER JOIN, OUTER JOIN, USING 조건절, ON 조건절
8 DIVIDE 현재 사용되지 않음

# JOIN의 정의
 - RDBMS의 경우 요구 사항 분석, 개념적 데이터 모델링, 논리적 데이터 모델링, 물리적 데이터 모델링 단계를 거치면서 엔티티 확정 및 정규화, 그리고 M:M 관계 분해 절차를 밟게된다. 정규화 과정에서 데이터 정합성과 데이터 저장 공간의 절약을 위해 엔티티를 최대한 분리하는 작업으로, 3차 정규형이나 보이스 코드 정규형까지 진행하게 된다. 이런 정규화를 거치면 하나의 주제에 관련 있는 엔티티가 여러 개로 나눠지게 되고, 이 엔티티들이 주로 테이블이 되는데, 이렇게 흩어진 데이터를 연결해서 원하는 데이터를 가져오는 작업을 말한다.


2. FROM 절 JOIN 형태
- INNER JOIN (기본 조인 방식)
- NATURAL JOIN
- USING 조건절
- ON 조건절
- CROSS JOIN
- OUTER JOIN

# 각 INNER JOIN 형태 비교
JOIN 형태 EQUI JOIN ALIAS JOIN 대상 컬럼 위치 변경 및 단일 출력 JOIN 대상 컬럼명 동일 기능 구현
INNER JOIN O O X may ALL
NATURAL JOIN O X O must Oracle
USING O X O must Oracle
ON O O X may ALL
CROSS JOIN O O    


3. INNER JOIN (Join의 기본 형태)

- Where 절 Join 조건
   SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;

- FROM 절 JOIN 조건
   SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME FROM EMP INNER JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO;

- INNER 키워드 생략 가능
   SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME FROM EMP  JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO;

4. NATRUAL JOIN - 두 테이블 간의 동일한 이름을 갖는 모든 컬럼에 대해 EQUI JOIN 수행
- Altibase도 안됨. Oracle만 됨
[ERR-31001 : SQL syntax error

line 1: parse error
SELECT TEAM_NAME, TEAM.STADIUM_ID, STADIUM_NAME FROM TEAM NATURAL JOIN STADIUM
                                                                       ^

]

- 공통 컬럼이 맨 선두에 위치해 있고, 공통 컬럼은 한번만 출력한다.
SQL> SELECT DEPTNO, EMPNO, ENAME, DNAME FROM EMP NATURAL JOIN DEPT;
    DEPTNO      EMPNO ENAME                DNAME
---------- ---------- -------------------- ----------------------------
        10       7782 CLARK                ACCOUNTING
        10       7839 KING                 ACCOUNTING
        10       7934 MILLER               ACCOUNTING
        20       7566 JONES                RESEARCH
        20       7902 FORD                 RESEARCH
        20       7876 ADAMS                RESEARCH
        20       7369 SMITH                RESEARCH
        20       7788 SCOTT                RESEARCH
        30       7521 WARD                 SALES
        30       7844 TURNER               SALES
        30       7499 ALLEN                SALES

    DEPTNO      EMPNO ENAME                DNAME
---------- ---------- -------------------- ----------------------------
        30       7900 JAMES                SALES
        30       7698 BLAKE                SALES
        30       7654 MARTIN               SALES

14 rows selected.

* INNER JOIN의 경우
SQL> SELECT * FROM EMP INNER JOIN DEPT ON EMP.DEPTNO=DEPT.DEPTNO;

     EMPNO ENAME                JOB                       MGR HIREDATE            SAL       COMM     DEPTNO     DEPTNO DNAME           LOC
---------- -------------------- ------------------ ---------- ------------ ---------- ---------- ---------- ---------- ---------------------------- --------------------------
      7782 CLARK                MANAGER                  7839 09-JUN-81          2450                    10         10 ACCOUNTING      NEW YORK
      7839 KING                 PRESIDENT                     17-NOV-81          5000                    10         10 ACCOUNTING      NEW YORK
      7934 MILLER               CLERK                    7782 23-JAN-82          1300                    10         10 ACCOUNTING      NEW YORK
      7566 JONES                MANAGER                  7839 02-APR-81          2975                    20         20 RESEARCH        DALLAS
      7902 FORD                 ANALYST                  7566 03-DEC-81          3000                    20         20 RESEARCH        DALLAS
      7876 ADAMS                CLERK                    7788 23-MAY-87          1100                    20         20 RESEARCH        DALLAS
      7369 SMITH                CLERK                    7902 17-DEC-80           800                    20         20 RESEARCH        DALLAS
      7788 SCOTT                ANALYST                  7566 19-APR-87          3000                    20         20 RESEARCH        DALLAS
      7521 WARD                 SALESMAN                 7698 22-FEB-81          1250        500         30         30 SALES           CHICAGO
      7844 TURNER               SALESMAN                 7698 08-SEP-81          1500          0         30         30 SALES           CHICAGO
      7499 ALLEN                SALESMAN                 7698 20-FEB-81          1600        300         30         30 SALES           CHICAGO

     EMPNO ENAME                JOB                       MGR HIREDATE            SAL       COMM     DEPTNO     DEPTNO DNAME           LOC
---------- -------------------- ------------------ ---------- ------------ ---------- ---------- ---------- ---------- ---------------------------- --------------------------
      7900 JAMES                CLERK                    7698 03-DEC-81           950                    30         30 SALES           CHICAGO
      7698 BLAKE                MANAGER                  7839 01-MAY-81          2850                    30         30 SALES           CHICAGO
      7654 MARTIN               SALESMAN                 7698 28-SEP-81          1250       1400         30         30 SALES           CHICAGO

14 rows selected.

- ALIAS나 테이블 명과 같은 접두사 사용 안됨.
SQL> SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME FROM EMP NATURAL JOIN DEPT;
SELECT EMP.DEPTNO, EMPNO, ENAME, DNAME FROM EMP NATURAL JOIN DEPT
       *
ERROR at line 1:
ORA-25155: column used in NATURAL join cannot have qualifier

- 동일한 구조의 테이블을 가지고 NATURAL JOIN과 INNER JOIN 결과를 비교해 보면...

SQL> select * from dept;

    DEPTNO DNAME                        LOC
---------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK
        20 RESEARCH                     DALLAS
        30 SALES                        CHICAGO
        40 OPERATIONS                   BOSTON

SQL> select * from dept_temp;

    DEPTNO DNAME                        LOC
---------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK
        20 RnD                          DALLAS
        30 MARKETING                    CHICAGO
        40 OPERATIONS                   BOSTON

SQL> SELECT * FROM DEPT NATURAL INNER JOIN DEPT_TEMP;

    DEPTNO DNAME                        LOC
---------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK
        40 OPERATIONS                   BOSTON

SQL> SELECT * FROM DEPT NATURAL JOIN DEPT_TEMP;

    DEPTNO DNAME                        LOC
---------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK
        40 OPERATIONS                   BOSTON

SQL> SELECT * FROM DEPT JOIN DEPT_TEMP ON DEPT.DEPTNO = DEPT_TEMP.DEPTNO AND DEPT.DNAME = DEPT_TEMP.DNAME AND DEPT.LOC = DEPT_TEMP.LOC;

    DEPTNO DNAME                        LOC                            DEPTNO DNAME                        LOC
---------- ---------------------------- -------------------------- ---------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK                           10 ACCOUNTING                   NEW YORK
        40 OPERATIONS                   BOSTON                             40 OPERATIONS                   BOSTON

SQL> SELECT * FROM DEPT, DEPT_TEMP WHERE DEPT.DEPTNO = DEPT_TEMP.DEPTNO AND DEPT.DNAME = DEPT_TEMP.DNAME AND DEPT.LOC = DEPT_TEMP.LOC;

    DEPTNO DNAME                        LOC                            DEPTNO DNAME                        LOC
---------- ---------------------------- -------------------------- ---------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK                           10 ACCOUNTING                   NEW YORK
        40 OPERATIONS                   BOSTON                             40 OPERATIONS                   BOSTON



5. USING 조건절

 - 기본적으로 NATURAL JOIN 방식으로 수행하지만, JOIN 대상 컬럼을 지정할 수 있다.
 - Altibase도 USING 지원 안된다.
  [ERR-31001 : SQL syntax error

line 1: parse error
SELECT TEAM_NAME, TEAM.STADIUM_ID, STADIUM_NAME FROM TEAM ,STADIUM USING(STADIUM_ID)
                                                                   ^   ^

]


- NATURAL JOIN 대상 컬럼은 선두에 위치하고 한번만 출력된다.
SQL> SELECT * FROM DEPT JOIN DEPT_TEMP USING (DEPTNO);

    DEPTNO DNAME                        LOC                        DNAME                        LOC
---------- ---------------------------- -------------------------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK                   ACCOUNTING                   NEW YORK
        20 RESEARCH                     DALLAS                     RnD                          DALLAS
        30 SALES                        CHICAGO                    MARKETING                    CHICAGO
        40 OPERATIONS                   BOSTON                     OPERATIONS                   BOSTON

- NATURAL JOIN 처럼 Alias나 테이블 명과 같은 접두사는 사용할 수 없다.

SQL> SELECT DEPT.DEPTNO, DEPT.DNAME, DEPT.LOC, DEPT_TEMP.DNAME, DEPT_TEMP.LOC FROM DEPT JOIN DEPT_TEMP USING (DEPTNO);
SELECT DEPT.DEPTNO, DEPT.DNAME, DEPT.LOC, DEPT_TEMP.DNAME, DEPT_TEMP.LOC FROM DEPT JOIN DEPT_TEMP USING (DEPTNO)
       *
ERROR at line 1:
ORA-25154: column part of USING clause cannot have qualifier


- DNAME이 바뀐 20, 30번 부서 출력 안됨.
SQL> SELECT * FROM DEPT JOIN DEPT_TEMP USING (DNAME);

DNAME                            DEPTNO LOC                            DEPTNO LOC
---------------------------- ---------- -------------------------- ---------- --------------------------
ACCOUNTING                           10 NEW YORK                           10 NEW YORK
OPERATIONS                           40 BOSTON                             40 BOSTON

- LOC,DEPTNO는 모두 일치
SQL> SELECT * FROM DEPT JOIN DEPT_TEMP USING (LOC, DEPTNO);

LOC                            DEPTNO DNAME                        DNAME
-------------------------- ---------- ---------------------------- ----------------------------
NEW YORK                           10 ACCOUNTING                   ACCOUNTING
DALLAS                             20 RESEARCH                     RnD
CHICAGO                            30 SALES                        MARKETING
BOSTON                             40 OPERATIONS                   OPERATIONS

- Join 대상 조건 중 DNAME이 불일치하여 단 2건 출력

SQL> SELECT * FROM DEPT JOIN DEPT_TEMP USING (DEPTNO, DNAME);

    DEPTNO DNAME                        LOC                        LOC
---------- ---------------------------- -------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK                   NEW YORK
        40 OPERATIONS                   BOSTON                     BOSTON


6. ON 조건절 : Join 조건절을 따로 뺄 수 있다.
 - NATURAL JOIN과 다르게 다른 이름을 가진 컬럼을 Join 대상으로 지정 가능
 - 임의의 조인 조건 지정 가능

SQL> SELECT E.EMPNO, E.ENAME, E.DEPTNO, D.DNAME FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO);

     EMPNO ENAME                    DEPTNO DNAME
---------- -------------------- ---------- ----------------------------
      7782 CLARK                        10 ACCOUNTING
      7839 KING                         10 ACCOUNTING
      7934 MILLER                       10 ACCOUNTING
      7566 JONES                        20 RESEARCH
      7902 FORD                         20 RESEARCH
      7876 ADAMS                        20 RESEARCH
      7369 SMITH                        20 RESEARCH
      7788 SCOTT                        20 RESEARCH
      7521 WARD                         30 SALES
      7844 TURNER                       30 SALES
      7499 ALLEN                        30 SALES

     EMPNO ENAME                    DEPTNO DNAME
---------- -------------------- ---------- ----------------------------
      7900 JAMES                        30 SALES
      7698 BLAKE                        30 SALES
      7654 MARTIN                       30 SALES

14 rows selected.

# Where 절과 혼용 가능
 SQL> SELECT E.ENAME, E.DEPTNO, D.DEPTNO, D.DNAME FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO)
WHERE E.DEPTNO = 30;

ENAME                    DEPTNO     DEPTNO DNAME
-------------------- ---------- ---------- ----------------------------
ALLEN                        30         30 SALES
WARD                         30         30 SALES
MARTIN                       30         30 SALES
BLAKE                        30         30 SALES
TURNER                       30         30 SALES
JAMES                        30         30 SALES

6 rows selected.

# ON 조건절 + 데이터 검증 조건 추가
SQL>  SELECT E.ENAME, E.MGR, D.DEPTNO, D.DNAME FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO AND E.MGR = 7698);

ENAME                       MGR     DEPTNO DNAME
-------------------- ---------- ---------- ----------------------------
ALLEN                      7698         30 SALES
WARD                       7698         30 SALES
MARTIN                     7698         30 SALES
TURNER                     7698         30 SALES
JAMES                      7698         30 SALES

SQL> SELECT E.ENAME, E.MGR, D.DEPTNO, D.DNAME FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO) WHERE E.MGR = 7698;

ENAME                       MGR     DEPTNO DNAME
-------------------- ---------- ---------- ----------------------------
ALLEN                      7698         30 SALES
WARD                       7698         30 SALES
MARTIN                     7698         30 SALES
TURNER                     7698         30 SALES
JAMES                      7698         30 SALES

# Join 대상 컬럼명이 동일할 경우 ON 조건절을 USING 절로 변환 가능

SELECT E.ENAME, E.MGR, D.DEPTNO, D.DNAME FROM EMP E JOIN DEPT D ON E.DEPTNO = D.DEPTNO;
SQL> SELECT ENAME, MGR, DEPTNO, DNAME FROM EMP JOIN DEPT USING(DEPTNO);

ENAME                       MGR     DEPTNO DNAME
-------------------- ---------- ---------- ----------------------------
CLARK                      7839         10 ACCOUNTING
KING                                    10 ACCOUNTING
MILLER                     7782         10 ACCOUNTING
JONES                      7839         20 RESEARCH
FORD                       7566         20 RESEARCH
ADAMS                      7788         20 RESEARCH
SMITH                      7902         20 RESEARCH
SCOTT                      7566         20 RESEARCH
WARD                       7698         30 SALES
TURNER                     7698         30 SALES
ALLEN                      7698         30 SALES

ENAME                       MGR     DEPTNO DNAME
-------------------- ---------- ---------- ----------------------------
JAMES                      7698         30 SALES
BLAKE                      7839         30 SALES
MARTIN                     7698         30 SALES

14 rows selected.


# Join 대상 컬럼명이 동일하지 않을 경우  ON 조건절을 USING 절로 변환 가능
SQL> select A.ENAME, B.MGR, A.DEPTNO, B.DEPTNO from EMP A JOIN EMP B ON A.EMPNO=B.EMPNO;

ENAME                       MGR     DEPTNO     DEPTNO
-------------------- ---------- ---------- ----------
SMITH
SMITH                      7902         20         20
ALLEN                      7698         30         30
WARD                       7698         30         30
JONES                      7839         20         20
MARTIN                     7698         30         30
BLAKE                      7839         30         30
CLARK                      7839         10         10
SCOTT                      7566         20         20
KING                                    10         10
TURNER                     7698         30         30

ENAME                       MGR     DEPTNO     DEPTNO
-------------------- ---------- ---------- ----------
ADAMS                      7788         20         20
JAMES                      7698         30         30
FORD                       7566         20         20
MILLER                     7782         10         10


16 rows selected.

SQL> select A.ENAME, B.MGR, A.DEPTNO, B.DEPTNO from EMP A, EMP B WHERE A.EMPNO=B.EMPNO;

ENAME                       MGR     DEPTNO     DEPTNO
-------------------- ---------- ---------- ----------
SMITH
SMITH                      7902         20         20
ALLEN                      7698         30         30
WARD                       7698         30         30
JONES                      7839         20         20
MARTIN                     7698         30         30
BLAKE                      7839         30         30
CLARK                      7839         10         10
SCOTT                      7566         20         20
KING                                    10         10
TURNER                     7698         30         30

ENAME                       MGR     DEPTNO     DEPTNO
-------------------- ---------- ---------- ----------
ADAMS                      7788         20         20
JAMES                      7698         30         30
FORD                       7566         20         20
MILLER                     7782         10         10


16 rows selected.

# 다중 테이블 JOIN

SQL> SELECT E.EMPNO, D.DEPTNO, D.DNAME, T.DNAME New_DNAME FROM EMP E JOIN DEPT D ON (E.DEPTNO = D.DEPTNO) JOIN DEPT_TEMP T ON (E.DEPTNO = T.DEPTNO);


SQL> SELECT E.EMPNO, D.DEPTNO, D.DNAME, T.DNAME New_DNAME FROM EMP E, DEPT D, DEPT_TEMP T WHERE E.DEPTNO = D.DEPTNO AND E.DEPTNO = T.DEPTNO;

     EMPNO     DEPTNO DNAME                        NEW_DNAME
---------- ---------- ---------------------------- ----------------------------
      7934         10 ACCOUNTING                   ACCOUNTING
      7839         10 ACCOUNTING                   ACCOUNTING
      7782         10 ACCOUNTING                   ACCOUNTING
      7788         20 RESEARCH                     RnD
      7369         20 RESEARCH                     RnD
      7876         20 RESEARCH                     RnD
      7902         20 RESEARCH                     RnD
      7566         20 RESEARCH                     RnD
      7654         30 SALES                        MARKETING
      7698         30 SALES                        MARKETING
      7900         30 SALES                        MARKETING

     EMPNO     DEPTNO DNAME                        NEW_DNAME
---------- ---------- ---------------------------- ----------------------------
      7499         30 SALES                        MARKETING
      7844         30 SALES                        MARKETING
      7521         30 SALES                        MARKETING

14 rows selected.


  - Altibase는 Join 절을 이용해 3개의 테이블까지 join 가능하지만, 그 이상이면 syntax error
iSQL> select *
    2 FROM SCHEDULE SC JOIN STADIUM ST
    3 ON SC.STADIUM_ID = ST.STADIUM_ID
    4 JOIN TEAM HT
    5 ON SC.HOMETEAM_ID = HT.TEAM_ID
    6 JOIN TEAM AT
    7 ON SC.AWAYTEAM_ID = AT.TEAM_ID
    8 WHERE HOME_SCORE > = AWAY_SCORE +3;
[ERR-31001 : SQL syntax error

line 6: parse error
JOIN TEAM AT
          ^^

]
 WHERE 조건절로 바꿔도 에러남
 iSQL> select *
    2 FROM SCHEDULE SC, STADIUM ST, TEAM HT, TEAM AT
    3 WHERE HOME_SCORE >= AWAY_SCORE +3
    4 AND SC.STADIUM_ID = ST.STADIUM_ID
    5 AND SC.HOMETEAM_ID = HT.TEAM_ID
    6 AND SC.AWAYTEAM_ID = AT.TEAM_ID;
[ERR-31001 : SQL syntax error

line 2: parse error
FROM SCHEDULE SC, STADIUM ST, TEAM HT, TEAM AT
                                            ^^

]

위 syntax error는 'AT' 라는 Alias 때문에 발생하는 것인데,
altibase 경우 범위 파티션에서 SPILT 할때 AT 키워드가 포함된다.
ALTER TABLE T1 SPILT PARTITION P3 AT ( 350) INTO (PARTITION P_200_350, PARTITION P_OVER_350);

Alias 명을 D 로 바꾸니 실행 잘됨 ㅋ (조인 대상 테이블이 4개로 제한되었다는 가설은 틀린 것이었음. ㅋㅋ)
iSQL> select count(*)
FROM SCHEDULE SC, STADIUM ST, TEAM HT, TEAM D
WHERE HOME_SCORE >= AWAY_SCORE +3
AND SC.STADIUM_ID = ST.STADIUM_ID
AND SC.HOMETEAM_ID = HT.TEAM_ID
AND SC.AWAYTEAM_ID = D.TEAM_ID;
iSQL>
iSQL> /
COUNT              
-----------------------
5                  
1 row selected.



7. CROSS JOIN : 테이블 간 Join 조건이 없는 경우 생길 수 있는 모든 데이터 조합, Cartesian product라고도 함. 결과는 M*N 건
용도 : DW에서 스타 스키마 구조의 개별 DIMEMSION을 FACT 컬럼과 JOIN하기 전에 모든 DEMENSION table의 CROSS PRODUCT를 먼저 구할때

SQL> select count(*) from emp;

  COUNT(*)
----------
        16

SQL> select count(*) from dept;

  COUNT(*)
----------
         4

SQL>
SQL> select count(*) from emp cross join dept;

  COUNT(*)
----------
        64

SQL> select count(*) from emp, dept;  <== 키워드를 생략해도 됨.

  COUNT(*)
----------
        64

 - 조인 조건이 추가되버리면 INNER JOIN과 같은 결과를 얻기 때문에 무의미함.
SQL> SELECT ENAME, DNAME FROM EMP CROSS JOIN DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;

ENAME                DNAME
-------------------- ----------------------------
CLARK                ACCOUNTING
KING                 ACCOUNTING
MILLER               ACCOUNTING
JONES                RESEARCH
FORD                 RESEARCH
ADAMS                RESEARCH
SMITH                RESEARCH
SCOTT                RESEARCH
WARD                 SALES
TURNER               SALES
ALLEN                SALES

ENAME                DNAME
-------------------- ----------------------------
JAMES                SALES
BLAKE                SALES
MARTIN               SALES

14 rows selected.



8. OUTER JOIN

  • 명시적인 OUTER JOIN 키워드 사용을 적극 권장
  • INNER JOIN 처럼 USING 조건이나, ON 절 필수적으로 사용
  • LEFT/RIGHT OUTER JOIN시 기준이되는 테이블이 조인 수행시 무조건 선행 테이블

# LEFT OUTER JOIN

iSQL> select * from tab1 left outer join tab2 on tab1.c1=tab2.c1;
C1  C2   C3          C1  C2          C3        
--------------------------------------------------------
A  AAB  111         A  10          AA        
B  AAC  123         B  10          AB        
C  ABA  222         C  10          AC        
D  ABB  233                                  
E  ABC  143                                  
5 rows selected.
------------------------------------------------------------
PROJECT ( COLUMN_COUNT: 6, TUPLE_SIZE: 70 )
 LEFT-OUTER-JOIN
  SCAN ( TABLE: TAB1, FULL SCAN, ACCESS: 5, SELF_ID: 1 )
  HASH ( ITEM_SIZE: 24, ITEM_COUNT: 3, BUCKET_COUNT: 1024, ACCESS: 5, SELF_ID: 3, REF_ID: 2 )
   SCAN ( TABLE: TAB2, FULL SCAN, ACCESS: 5, SELF_ID: 2 )
------------------------------------------------------------

iSQL> select /*+ USE_NL(A,B) */ * from tab1 a left join tab2 b  on a.c1=b.c1;
C1  C2   C3          C1  C2          C3        
--------------------------------------------------------
A  AAB  111         A  10          AA        
B  AAC  123         B  10          AB        
C  ABA  222         C  10          AC        
D  ABB  233                                  
E  ABC  143                                  
5 rows selected.
------------------------------------------------------------
PROJECT ( COLUMN_COUNT: 6, TUPLE_SIZE: 70 )
 LEFT-OUTER-JOIN
  SCAN ( TABLE: TAB1 A, FULL SCAN, ACCESS: 5, SELF_ID: 1 )
  SCAN ( TABLE: TAB2 B, FULL SCAN, ACCESS: 17, SELF_ID: 2 )
------------------------------------------------------------

<오라클 결과>

SQL> select * from tab1 left outer join tab2 on tab1.c1=tab2.c1;

C1 C2             C3 C1         C2 C3
-- ------ ---------- -- ---------- --------------------
A  AAB           111 A          10 AA
B  AAC           123 B          10 AB
C  ABA           222 C          10 AC
E  ABC           143
D  ABB           233


# RIGTH OUTER JOIN

iSQL> select /*+ USE_NL(A,B) */ * from tab1 a right outer join tab2 b  on a.c1=b.c1;
C1  C2   C3          C1  C2          C3        
--------------------------------------------------------
A  AAB  111         A  10          AA        
B  AAC  123         B  10          AB        
C  ABA  222         C  10          AC        
3 rows selected.
------------------------------------------------------------
PROJECT ( COLUMN_COUNT: 6, TUPLE_SIZE: 70 )
 LEFT-OUTER-JOIN         <------------------ RIGHT OUTER JOIN 연산자가 아니다~!!!!
  SCAN ( TABLE: TAB2 B, FULL SCAN, ACCESS: 3, SELF_ID: 2 )
  SCAN ( TABLE: TAB1 A, FULL SCAN, ACCESS: 15, SELF_ID: 1 )
------------------------------------------------------------


# FULL OUTER JOIN

  • LEFT OUTER JOIN과 RIGHT OUTER JOIN의 합집합
  • UNION ALL이 아닌 UNION과 같은 기능이므로, 중복 데이터 삭제

< Full outer join 테스트 :  left outer join 결과와 right outer join 결과를 union하여 비교>

SQL> UPDATE DEPT_TEMP SET DEPTNO = DEPTNO + 20;

4 rows updated.

SQL> SELECT * FROM DEPT_TEMP;

    DEPTNO DNAME                        LOC
---------- ---------------------------- --------------------------
        30 ACCOUNTING                   NEW YORK
        40 RnD                          DALLAS
        50 MARKETING                    CHICAGO
        60 OPERATIONS                   BOSTON
SQL> SELECT * FROM DEPT FULL OUTER JOIN DEPT_TEMP ON DEPT.DEPTNO = DEPT_TEMP.DEPTNO;

    DEPTNO DNAME                        LOC                            DEPTNO DNAME                        LOC
---------- ---------------------------- -------------------------- ---------- ---------------------------- --------------------------
        30 SALES                        CHICAGO                            30 ACCOUNTING                   NEW YORK
        40 OPERATIONS                   BOSTON                             40 RnD                          DALLAS
                                                                           50 MARKETING                    CHICAGO
                                                                           60 OPERATIONS                   BOSTON
        20 RESEARCH                     DALLAS
        10 ACCOUNTING                   NEW YORK

6 rows selected.

SQL> SELECT L.DEPTNO, L.DNAME, L.LOC, R.DEPTNO, R.DNAME, R.LOC FROM DEPT L LEFT OUTER JOIN DEPT_TEMP R ON L.DEPTNO = R.DEPTNO UNION SELECT L.DEPTNO, L.DNAME, L.LOC, R.DEPTNO, R.DNAME, R.LOC FROM DEPT L RIGHT OUTER JOIN DEPT_TEMP R ON L.DEPTNO = R.DEPTNO;

    DEPTNO DNAME                        LOC                            DEPTNO DNAME                        LOC
---------- ---------------------------- -------------------------- ---------- ---------------------------- --------------------------
        10 ACCOUNTING                   NEW YORK
        20 RESEARCH                     DALLAS
        30 SALES                        CHICAGO                            30 ACCOUNTING                   NEW YORK
        40 OPERATIONS                   BOSTON                             40 RnD                          DALLAS
                                                                           50 MARKETING                    CHICAGO
                                                                           60 OPERATIONS                   BOSTON

6 rows selected.


- Plan상으로 봤을 때 left outer join과 동일하다.
iSQL> select  * from tab1 a full outer join tab2 b  on a.c1=b.c1;
C1  C2   C3          C1  C2          C3        
--------------------------------------------------------
A  AAB  111         A  10          AA        
B  AAC  123         B  10          AB        
C  ABA  222         C  10          AC        
E  ABC  143                                  
D  ABB  233                                  
                    F  10          BC        
6 rows selected.
------------------------------------------------------------
PROJECT ( COLUMN_COUNT: 6, TUPLE_SIZE: 70 )
 FULL-OUTER-JOIN
  SCAN ( TABLE: TAB1 A, FULL SCAN, ACCESS: 6, SELF_ID: 1 )
  HASH ( ITEM_SIZE: 24, ITEM_COUNT: 4, BUCKET_COUNT: 1024, ACCESS: 6, SELF_ID: 3, REF_ID: 2 )
   SCAN ( TABLE: TAB2 B, FULL SCAN, ACCESS: 6, SELF_ID: 2 )
------------------------------------------------------------

iSQL> select  * from tab1 a left outer join tab2 b  on a.c1=b.c1
union
select  * from tab1 a right outer join tab2 b  on a.c1=b.c1;
iSQL> /
C1  C2   C3          C1  C2          C3        
--------------------------------------------------------
A  AAB  111         A  10          AA        
B  AAC  123         B  10          AB        
C  ABA  222         C  10          AC        
E  ABC  143                                  
D  ABB  233                                  
                    F  10          BC        
6 rows selected.
------------------------------------------------------------
PROJECT ( COLUMN_COUNT: 6, TUPLE_SIZE: 70 )
 DISTINCT ( ITEM_SIZE: 88, ITEM_COUNT: 6, BUCKET_COUNT: 1024, ACCESS: 6, SELF_ID: 8, REF_ID: 5 )
  VIEW ( ACCESS: 9, SELF_ID: 5 )
   BAG-UNION
    PROJECT ( COLUMN_COUNT: 6, TUPLE_SIZE: 70 )
     LEFT-OUTER-JOIN
      SCAN ( TABLE: TAB1 A, FULL SCAN, ACCESS: 5, SELF_ID: 1 )
      HASH ( ITEM_SIZE: 24, ITEM_COUNT: 4, BUCKET_COUNT: 1024, ACCESS: 5, SELF_ID: 6, REF_ID: 2 )
       SCAN ( TABLE: TAB2 B, FULL SCAN, ACCESS: 6, SELF_ID: 2 )
    PROJECT ( COLUMN_COUNT: 6, TUPLE_SIZE: 70 )
     LEFT-OUTER-JOIN      <------------------ RIGHT OUTER JOIN 연산자가 아니다~!!!!
      SCAN ( TABLE: TAB2 B, FULL SCAN, ACCESS: 4, SELF_ID: 4 )
      HASH ( ITEM_SIZE: 24, ITEM_COUNT: 5, BUCKET_COUNT: 1024, ACCESS: 4, SELF_ID: 7, REF_ID: 3 )
       SCAN ( TABLE: TAB1 A, FULL SCAN, ACCESS: 6, SELF_ID: 3 )
------------------------------------------------------------

댓글 없음:

댓글 쓰기