조인
조인(Join)은 둘 이상의 테이블을 연결해 하나의 결과 집합으로 만드는 연산이다. 이 문서는 WHERE 절에 조인 조건을 쓰는 Oracle 전통 방식을 다루며, ANSI 표준 문법은 표준 조인에서 다룬다.
예제 테이블
EMP
| EMPNO | ENAME | SAL | MGR | DEPTNO |
|---|---|---|---|---|
| 7369 | SMITH | 800 | 7902 | 20 |
| 7499 | ALLEN | 1600 | 7698 | 30 |
| 7698 | BLAKE | 2850 | 7839 | 30 |
| 7839 | KING | 5000 | NULL | 10 |
| 7902 | FORD | 3000 | 7839 | 20 |
| 7999 | LEE | 1200 | 7698 | NULL |
DEPT
| DEPTNO | DNAME | LOC |
|---|---|---|
| 10 | ACCOUNTING | NEW YORK |
| 20 | RESEARCH | DALLAS |
| 30 | SALES | CHICAGO |
| 40 | OPERATIONS | BOSTON |
SALGRADE
| GRADE | LOSAL | HISAL |
|---|---|---|
| 1 | 700 | 1200 |
| 2 | 1201 | 1400 |
| 3 | 1401 | 2000 |
| 4 | 2001 | 3000 |
| 5 | 3001 | 9999 |
눈여겨볼 데이터는 두 가지다. LEE는 부서가 NULL이고, 40번 부서에는 사원이 없다. 이 두 행이 조인 종류마다 결과에 나오는지 빠지는지가 핵심이다.
조인의 개념
- 왜 쓰나 정규화로 분리된 테이블을 다시 연결해 필요한 정보를 함께 조회하기 위해 쓴다.
- PK–FK 불필요 PK–FK 관계가 없어도 컬럼 값의 논리적 관계만 있으면 조인할 수 있다.
- 두 집합씩 FROM 절에 여러 테이블을 나열해도 조인은 내부적으로 두 집합씩 순차적으로 수행된다.
- 컬럼 구분 여러 테이블에 같은 이름의 컬럼이 있으면
테이블명.컬럼또는별칭.컬럼으로 반드시 구분해야 한다(모호성 오류 방지).
조인 종류 한눈에 보기
EQUI JOIN(등가 조인)
두 테이블의 컬럼 값이 정확히 일치(=)하는 행끼리 연결한다. 가장 많이 쓰는 조인이다.
SELECT E.ENAME, E.DEPTNO, D.DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO;
| ENAME | DEPTNO | DNAME |
|---|---|---|
| SMITH | 20 | RESEARCH |
| ALLEN | 30 | SALES |
| BLAKE | 30 | SALES |
| KING | 10 | ACCOUNTING |
| FORD | 20 | RESEARCH |
- DEPTNO가 NULL인 LEE는 어떤 DEPT 행과도 같지 않으므로 제외된다.
- 사원이 없는 40번 부서(OPERATIONS)도 결과에 나오지 않는다.
- 조인 조건 외의 일반 조건은 AND로 추가한다. 예:
AND D.LOC = 'DALLAS'→ SMITH, FORD.
Non-EQUI JOIN(비등가 조인)
=가 아닌 BETWEEN, >, <= 등의 연산자로 연결한다. 값의 범위로 등급을 구할 때 주로 쓴다.
SELECT E.ENAME, E.SAL, S.GRADE
FROM EMP E, SALGRADE S
WHERE E.SAL BETWEEN S.LOSAL AND S.HISAL;
| ENAME | SAL | GRADE |
|---|---|---|
| SMITH | 800 | 1 |
| ALLEN | 1600 | 3 |
| BLAKE | 2850 | 4 |
| KING | 5000 | 5 |
| FORD | 3000 | 4 |
| LEE | 1200 | 1 |
- FORD의 3000은 HISAL 경계값이지만 BETWEEN은 양 끝을 포함하므로 4등급이다.
- LEE는 부서가 NULL이어도 SAL로 연결하므로 결과에 나온다.
등급 구간 설계
등급 구간이 겹치거나 비어 있으면 중복 행이나 누락이 생길 수 있다. 예를 들어 1등급이 700~1250이면 1201~1250 사이 급여는 1·2등급 두 행으로 나온다.
3개 이상 테이블 조인
SELECT E.ENAME, D.DNAME, S.GRADE
FROM EMP E, DEPT D, SALGRADE S
WHERE E.DEPTNO = D.DEPTNO
AND E.SAL BETWEEN S.LOSAL AND S.HISAL;
- EMP 6행
- + DEPT E.DEPTNO = D.DEPTNO → 5행
- + SALGRADE SAL BETWEEN → 5행
| ENAME | DNAME | GRADE |
|---|---|---|
| SMITH | RESEARCH | 1 |
| ALLEN | SALES | 3 |
| BLAKE | SALES | 4 |
| KING | ACCOUNTING | 5 |
| FORD | RESEARCH | 4 |
- N개 테이블을 조인하려면 최소 N-1개의 조인 조건이 필요하다. 3개 테이블이면 최소 2개다.
- 조인 조건이 부족하면 연결되지 않은 테이블과 카티션 곱이 발생한다.
시험 포인트: "테이블 N개를 조인할 때 필요한 최소 조인 조건 수"는 N-1개다. 복합키로 연결하는 경우 조건식 개수는 더 늘어날 수 있다.
SELF JOIN
하나의 테이블을 별칭을 달리해 두 번 사용하여 자기 자신과 조인한다. 사원–관리자처럼 같은 테이블 안의 계층 관계를 표현할 때 쓴다. E는 "사원 역할의 EMP", M은 "관리자 역할의 EMP"다.
flowchart BT
SMITH["SMITH<br/>MGR 7902"] -->|"E.MGR = M.EMPNO"| FORD["FORD<br/>7902"]
ALLEN["ALLEN<br/>MGR 7698"] --> BLAKE["BLAKE<br/>7698"]
LEE["LEE<br/>MGR 7698"] --> BLAKE
FORD --> KING["KING<br/>7839 · MGR NULL"]
BLAKE --> KING
classDef hl fill:#fef3c7,stroke:#f59e0b,color:#451a03
class KING hl
SELECT E.ENAME AS 사원, M.ENAME AS 관리자
FROM EMP E, EMP M
WHERE E.MGR = M.EMPNO;
| 사원 | 관리자 |
|---|---|
| SMITH | FORD |
| ALLEN | BLAKE |
| BLAKE | KING |
| FORD | KING |
| LEE | BLAKE |
- 별칭 없이 같은 테이블을 두 번 쓰면 컬럼을 구분할 수 없어 오류가 발생하므로 별칭은 필수다.
- MGR이 NULL인 KING은 관리자가 없으므로 제외된다. KING까지 출력하려면 OUTER JOIN을 쓴다.
- 여러 단계 상하 관계는 계층형 질의로 처리한다.
OUTER JOIN과 Oracle (+) 표기
EQUI JOIN에서 조건을 만족하지 못해 빠지는 행도 결과에 포함시키는 조인이다. Oracle은 데이터가 없는 쪽(NULL로 채워질 쪽) 컬럼 뒤에 (+)를 붙인다.
- E.DEPTNO = D.DEPTNO(+) DEPT 쪽이 부족한 쪽. EMP가 기준이므로 부서 없는 LEE도 나온다. LEFT OUTER JOIN과 같다.
- E.DEPTNO(+) = D.DEPTNO EMP 쪽이 부족한 쪽. DEPT가 기준이므로 사원 없는 40번 부서도 나온다. RIGHT OUTER JOIN과 같다.
-- EMP 기준: 부서가 없는 사원도 포함 (LEFT OUTER JOIN과 같음)
SELECT E.ENAME, D.DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO(+);
| ENAME | DNAME |
|---|---|
| SMITH | RESEARCH |
| ALLEN | SALES |
| BLAKE | SALES |
| KING | ACCOUNTING |
| FORD | RESEARCH |
| LEE | NULL |
-- DEPT 기준: 사원이 없는 부서도 포함 (RIGHT OUTER JOIN과 같음)
SELECT E.ENAME, D.DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO(+) = D.DEPTNO;
결과는 EQUI JOIN 5행 + 40번 부서(ENAME NULL, DNAME OPERATIONS) 1행으로 총 6행이다.
(+) 사용 시 주의사항
(+) 표기의 제약
- 양쪽에
(+)를 동시에 붙일 수 없다. FULL OUTER JOIN은 ANSI 문법이나 UNION으로 구현한다. (+)조건을 OR로 다른 조건과 결합할 수 없다.- 기준 테이블의 반대편(NULL이 채워질 쪽) 테이블에 일반 조건을 추가할 때도
(+)를 붙여야 OUTER JOIN이 유지된다.
-- D.LOC 조건에 (+)가 없으면 NULL 행이 걸러져 사실상 INNER JOIN이 됨
SELECT E.ENAME, D.DNAME
FROM EMP E, DEPT D
WHERE E.DEPTNO = D.DEPTNO(+)
AND D.LOC(+) = 'DALLAS';
위 SQL은 사원 6명이 모두 나오고, DALLAS 부서(RESEARCH)에 속한 SMITH와 FORD만 DNAME이 채워지며 나머지는 NULL이다.
시험 포인트: (+)는 "기준 테이블"이 아니라 "부족한 쪽", 즉 NULL이 채워질 테이블 컬럼에 붙인다.
E.DEPTNO = D.DEPTNO(+)는 EMP가 기준인 LEFT OUTER JOIN이다.
CROSS JOIN(카티션 곱)
조인 조건이 없으면 두 테이블의 모든 행 조합이 만들어진다. 결과 행 수는 두 테이블 행 수의 곱이다.
SELECT E.ENAME, D.DNAME
FROM EMP E, DEPT D; -- 6 × 4 = 24행
언제 쓰나
의도적으로 쓰는 경우(테스트 데이터 생성, 모든 조합 생성)도 있지만, 대부분은 조인 조건 누락에 의한 실수다.
결과 행 수 계산
조인 결과 행 수는 조건을 만족하는 행 쌍의 개수다. 값이 중복되면 중복된 만큼 곱해져 늘어난다.
T1
| A |
|---|
| 1 |
| 2 |
| 3 |
T2
| A | B |
|---|---|
| 1 | x |
| 1 | y |
| 2 | z |
| 4 | w |
| SQL | 행 수 | 설명 |
|---|---|---|
WHERE T1.A = T2.A |
3 | 1이 2건, 2가 1건 매칭 |
WHERE T1.A = T2.A(+) |
4 | 매칭 3건 + T1의 3(짝 없음) 1건 |
WHERE T1.A(+) = T2.A |
4 | 매칭 3건 + T2의 4(짝 없음) 1건 |
| FULL OUTER (ANSI) | 5 | 매칭 3건 + T1의 3 + T2의 4 |
| 조건 없음(CROSS) | 12 | 3 × 4 |
행 수 계산 공식
INNER = 매칭 쌍 수, LEFT/RIGHT = INNER + 기준 쪽에만 있는 행 수, FULL = INNER + 왼쪽에만 + 오른쪽에만, CROSS = M × N. 매칭 쌍을 셀 때는 중복 값(T2의 1이 2건)을 빠뜨리지 말자.
핵심 요약
- 조인은 두 집합씩 순차적으로 수행되며, PK–FK 관계가 없어도 가능하다.
- EQUI JOIN은
=로, Non-EQUI JOIN은 BETWEEN·부등호로 연결한다. - N개 테이블 조인에는 최소 N-1개의 조인 조건이 필요하다.
- SELF JOIN은 같은 테이블에 서로 다른 별칭을 붙여 사용한다.
- Oracle OUTER JOIN은 NULL이 채워질 쪽 컬럼에 (+)를 붙이며, 양쪽 동시 사용은 불가하다.
- OUTER JOIN 시 반대편 테이블의 일반 조건에도 (+)를 붙여야 결과가 유지된다.
- 조인 조건이 없으면 카티션 곱(M × N행)이 발생한다.