2과목 · SQL 기본 및 활용·11장
JOIN
INNER/OUTER/CROSS/NATURAL/USING 조인, SELF JOIN, 카티션곱까지 조인 전 영역을 정리합니다.
1. JOIN이란
두 개 이상의 테이블을 공통 컬럼 기준으로 결합해 하나의 결과 집합을 만드는 연산.
2. INNER JOIN — 교집합
양쪽 모두에 일치하는 행만 반환.
SELECT e.name, d.name AS dept
FROM emp e
INNER JOIN dept d ON e.dept_id = d.dept_id;
INNER 키워드는 생략 가능: JOIN = INNER JOIN.
3. OUTER JOIN — 한쪽 전부 + 매칭
LEFT OUTER JOIN
왼쪽 테이블 전부 + 오른쪽 매칭. 매칭 없으면 오른쪽은 NULL.
SELECT e.name, d.name AS dept
FROM emp e
LEFT OUTER JOIN dept d ON e.dept_id = d.dept_id;
RIGHT OUTER JOIN
오른쪽 전부 + 왼쪽 매칭. 실무에선 LEFT로 뒤집는 편이 가독성 좋음.
FULL OUTER JOIN
양쪽 모두의 행을 보존. 매칭이 없으면 반대편은 NULL.
SELECT e.name, d.name
FROM emp e FULL OUTER JOIN dept d ON e.dept_id = d.dept_id;
4. CROSS JOIN — 카티션 곱
모든 조합을 생성. 필터가 없으면 행 수가 폭발.
SELECT e.name, d.name FROM emp e CROSS JOIN dept d;
-- emp 100행 × dept 10행 = 1,000행
5. NATURAL JOIN vs USING
NATURAL JOIN
이름이 같은 컬럼을 자동으로 조인 조건으로 사용. 편하지만 스키마 변경에 취약.
SELECT * FROM emp NATURAL JOIN dept;
USING(col)
이름이 같은 컬럼 중 명시한 컬럼만 조인 키로.
SELECT * FROM emp JOIN dept USING (dept_id);
-- 결과에서 dept_id는 한 번만 나타남
ON 조건 (가장 명시적)
SELECT e.*, d.name
FROM emp e JOIN dept d ON e.dept_id = d.dept_id;
6. SELF JOIN
같은 테이블을 두 번 참조해 계층·비교 관계를 표현.
-- 각 사원과 그 상사 이름
SELECT e.name AS emp, m.name AS manager
FROM emp e
LEFT JOIN emp m ON e.manager_id = m.emp_id;
7. 다중 조인의 순서
SQL 논리상 순서는 중요하지 않지만, 옵티마이저가 실행 계획을 짤 때 통계와 카디널리티를 보고 정렬합니다. 개발자는 ON 조건을 명확히 쓰는 것이 핵심.
SELECT e.name, d.name AS dept, l.city
FROM emp e
JOIN dept d ON e.dept_id = d.dept_id
JOIN location l ON d.location_id = l.location_id;
8. Oracle (+) 구문 vs ANSI JOIN
Oracle 전용 구식 구문:
-- LEFT OUTER JOIN
SELECT e.name, d.name
FROM emp e, dept d
WHERE e.dept_id = d.dept_id(+);
(+)는 반대편에 붙여 해당 쪽을 바깥 테이블로 만든다.- 가독성 떨어지고 ANSI 표준도 아니라 ANSI JOIN 권장.
9. 조인 함정
1. 중복 증가
-- 자식이 여럿이면 부모 행이 여러 번 복제됨
SELECT o.id, o.amount, i.qty
FROM orders o JOIN order_item i ON o.id = i.order_id;
-- 원치 않는 합계 왜곡 → DISTINCT/집계 필요
2. NULL과 OUTER JOIN
WHERE 절에 OUTER JOIN 바깥 테이블 조건을 걸면 OUTER가 사실상 INNER로 동작.
-- ❌ d.active 조건이 WHERE라 dept가 없는 emp는 사라짐
SELECT * FROM emp e
LEFT JOIN dept d ON e.dept_id = d.dept_id
WHERE d.active = 'Y';
-- ✅ ON 절에 조건을 넣어 OUTER를 유지
SELECT * FROM emp e
LEFT JOIN dept d ON e.dept_id = d.dept_id AND d.active = 'Y';
10. 자주 출제되는 포인트
- INNER / LEFT / RIGHT / FULL OUTER의 의미와 NULL 보존.
NATURAL JOIN: 이름이 같은 컬럼 자동 조인.USING(col): 명시 조인 키, 결과 컬럼 1회.CROSS JOIN= 카티션 곱.- OUTER 조건을 WHERE로 옮기면 INNER가 되어버릴 수 있음.
11. 요약 체크리스트
- INNER/LEFT/RIGHT/FULL/CROSS의 결과 차이를 예로 설명할 수 있다.
- NATURAL JOIN과 USING의 차이를 안다.
- SELF JOIN으로 계층 관계를 조회할 수 있다.
- OUTER JOIN 조건을 WHERE로 옮겼을 때의 함정을 이해한다.