표준 조인과 Outer Join
INNER·LEFT·RIGHT·FULL OUTER JOIN과 ON·WHERE 조건 위치가 보존 행에 미치는 영향을 익힌다.
핵심 요약
INNER·LEFT·RIGHT·FULL OUTER JOIN과 ON·WHERE 조건 위치가 보존 행에 미치는 영향을 익힌다.
핵심 질문
- 표준 조인과 Outer Join에서 반드시 구분해야 할 개념과 결과 규칙은 무엇인가?
- 0건·1건·여러 건과 NULL·동점·중복 데이터에서 결과가 어떻게 달라지는가?
- 비슷해 보이는 문법과 결과가 같아지는 조건, 달라지는 조건은 무엇인가?
- 작은 샘플 데이터를 이용해 결과를 실수 없이 예측하는 순서는 무엇인가?
학습 목표
- ANSI 표준 조인 문법을 읽고 같은 결과의 관계를 설명한다.
- Outer Join에서 ON과 WHERE의 필터 차이를 예측한다.
개념 지도
보존할 테이블 결정 → ON에서 관계 조건 → WHERE에서 최종 필터 → NULL 보존 확인
핵심 내용
INNER JOIN은 양쪽에 매칭되는 행만 반환한다. LEFT OUTER JOIN은 왼쪽 전체를 보존하고 매칭되지 않은 오른쪽 컬럼을 NULL로 채운다. RIGHT는 반대, FULL은 양쪽 미매칭 행을 모두 보존한다.
SELECT d.deptno, e.empno
FROM dept d
LEFT JOIN emp e
ON e.deptno = d.deptno
AND e.status = 'ACTIVE';
위 조건은 모든 부서를 보존하면서 활성 사원만 조인한다. 반면 e.status = 'ACTIVE'를 WHERE에 두면 NULL로 확장된 미매칭 행이 제거되어 결과가 사실상 Inner Join처럼 바뀔 수 있다.
NATURAL JOIN과 USING은 같은 이름의 컬럼을 간결하게 연결하지만, 스키마 변경으로 예상치 못한 컬럼이 조인에 포함될 수 있어 명시적 ON이 이해하기 쉽다.
흔한 오해와 주의점
- Outer Join의 보존 기준 테이블 방향을 먼저 확인한다.
- 오른쪽 테이블 조건을 WHERE에 두어 외부 조인 의미를 없애는 문제를 주의한다.
- Oracle 구문
(+)에서는 표시 위치와 조건 제약을 정확히 읽되, 새 SQL은 ANSI 문법이 명확하다.
문항 풀이 보강: 외부 조인 결과를 손으로 세기
LEFT OUTER JOIN은 왼쪽 각 행에 대해 오른쪽 매칭을 모두 출력하고, 매칭이 없을 때 오른쪽을 NULL로 채운 행 하나를 만든다. 오른쪽에 같은 키가 여러 건이면 왼쪽 행도 그 수만큼 복제된다.
FROM tab1 a
LEFT JOIN tab2 b
ON a.c1 = b.c1
AND b.c2 BETWEEN 1 AND 3
b.c2 조건은 ON에 있으므로 조건을 만족하지 않는 오른쪽 행만 매칭에서 제외할 뿐, 왼쪽 행 자체는 보존한다. 이 조건을 WHERE로 옮기면 NULL 확장 행도 제거될 수 있다.
Oracle (+)를 ANSI로 바꾸기
-- Oracle 구문
WHERE a.board_id = b.board_id(+)
AND b.use_yn(+) = 'Y'
-- ANSI 구문
FROM board a
LEFT JOIN post b
ON b.board_id = a.board_id
AND b.use_yn = 'Y'
선택 테이블의 조건을 WHERE에 남기면 외부 조인 의미가 달라질 수 있다.
FULL OUTER JOIN의 집합 표현
FULL OUTER JOIN은 LEFT JOIN UNION RIGHT JOIN으로 표현할 수 있다. 또 Inner Join 결과, 왼쪽 미매칭, 오른쪽 미매칭을 UNION ALL로 합쳐도 같은 결과를 만들 수 있다. 단, UNION의 중복 제거가 원래 결과의 중복을 없애지 않는지 키와 데이터 중복을 확인한다.
ON과 WHERE 위치가 결과를 바꾸는 예
-- 부서 전체를 보존하고 ACTIVE 사원만 연결
SELECT d.deptno, e.empno
FROM dept d
LEFT JOIN emp e
ON e.deptno = d.deptno
AND e.status = 'ACTIVE';
-- WHERE가 NULL 보존 행을 제거해 사실상 Inner Join
SELECT d.deptno, e.empno
FROM dept d
LEFT JOIN emp e
ON e.deptno = d.deptno
WHERE e.status = 'ACTIVE';
Outer Join에서 오른쪽 테이블의 제한 조건을 ON에 둘지 WHERE에 둘지는 단순 스타일이 아니라 보존할 행의 의미를 결정한다.
표준 Join 종류
| 문법 | 반환 의미 |
|---|---|
INNER JOIN | 양쪽 Match 조합 |
LEFT/RIGHT OUTER JOIN | 지정한 쪽 미매칭 행 보존 |
FULL OUTER JOIN | 양쪽 미매칭 행 모두 보존 |
CROSS JOIN | Cartesian Product |
NATURAL JOIN | 같은 이름 Column 자동 연결—운영 SQL에서는 변경 위험 큼 |
USING(deptno)는 같은 이름 Column을 한 번만 출력하는 편의가 있지만 Table Alias로 해당 Column을 수식하는 규칙을 확인한다.
중복 검증
부모 한 행에 자식 여러 행이 Match하면 부모 Column도 여러 번 나온다. DISTINCT로 숨기기 전에 결과 Grain이 부모 1행인지 자식 조합 1행인지 정한다. 존재 여부만 필요하면 EXISTS를 검토한다.
결과를 검증하는 순서
- 각 Query Block이 만드는 한 행의 의미를 먼저 적습니다.
- 조건을 적용하기 전 원본 행과 적용 후 남는 행을 작은 표로 그립니다.
- NULL 비교가
TRUE,FALSE,UNKNOWN중 무엇인지 구분합니다. - 중복 제거, 그룹화, 정렬과 행 제한이 적용되는 순서를 확인합니다.
- 데이터가 0건·1건·여러 건일 때도 같은 규칙이 성립하는지 검증합니다.
실무와 시험에서 함께 확인할 항목
ORDER BY가 없다면 결과 순서를 가정하지 않습니다.- 문자열·숫자·날짜 비교에서는 데이터 타입과 명시적 형변환을 확인합니다.
- 같은 결과처럼 보이는 SQL도 NULL과 중복이 있을 때 달라질 수 있습니다.
- 문법을 외우기 전에 샘플 데이터 3~5행으로 결과를 직접 계산합니다.
마지막 점검
- 작성 순서가 아니라 SQL의 논리적 처리 순서로 결과를 계산합니다.
- NULL을 0이나 빈 값과 같은 것으로 취급하지 않습니다.
ORDER BY가 없는 결과 순서와 DISTINCT 없는 중복 제거를 가정하지 않습니다.- 비슷한 문법은 0건·다건·NULL 데이터를 넣어 결과가 정말 같은지 확인합니다.
복습 문제
- 사원이 없는 부서도 출력하려면 어느 테이블을 보존해야 하는가?
- ON의 오른쪽 조건을 WHERE로 옮기면 미매칭 행에 어떤 일이 생기는가?
- 샘플 데이터 3행으로 결과를 직접 계산할 수 있는가?
- NULL이 포함될 때 결과가 달라지는 지점은 어디인가?