[Oracle] 04. JOIN (테이블 결합)
Oracle에서 여러 테이블을 결합하여 데이터를 조회하는 JOIN의 종류와 사용법을 정리합니다.
Oracle 전용 구문과 ANSI 표준 구문을 함께 설명합니다.
샘플 데이터 준비
CREATE TABLE departments (
id NUMBER(10) PRIMARY KEY,
name VARCHAR2(30) NOT NULL
);
CREATE TABLE employees (
id NUMBER(10) PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
dept_id NUMBER(10),
salary NUMBER(12,2),
CONSTRAINT fk_emp_dept FOREIGN KEY (dept_id) REFERENCES departments(id)
);
INSERT INTO departments VALUES (1, '개발팀');
INSERT INTO departments VALUES (2, '기획팀');
INSERT INTO departments VALUES (3, '디자인팀');
INSERT INTO departments VALUES (4, '인사팀');
INSERT INTO employees VALUES (1, '홍길동', 1, 5000000);
INSERT INTO employees VALUES (2, '김철수', 2, 4500000);
INSERT INTO employees VALUES (3, '이영희', 1, 5500000);
INSERT INTO employees VALUES (4, '박민수', 3, 4800000);
INSERT INTO employees VALUES (5, '최지은', NULL, 4000000);
COMMIT;
JOIN 종류 한눈에 보기
| JOIN 종류 | ANSI 표준 | Oracle 전용 구문 |
|---|---|---|
| INNER JOIN | A INNER JOIN B ON ... |
WHERE A.col = B.col |
| LEFT OUTER JOIN | A LEFT JOIN B ON ... |
WHERE A.col = B.col(+) |
| RIGHT OUTER JOIN | A RIGHT JOIN B ON ... |
WHERE A.col(+) = B.col |
| FULL OUTER JOIN | A FULL JOIN B ON ... |
Oracle 전용 구문 없음 |
| CROSS JOIN | A CROSS JOIN B |
FROM A, B (조건 없이) |
| SELF JOIN | 동일 | 동일 |
ANSI 표준 구문 사용을 권장합니다. 가독성이 좋고 다른 DBMS와 호환됩니다.
INNER JOIN
-- ANSI 표준 (권장)
SELECT e.name AS 직원명, d.name AS 부서명, e.salary
FROM employees e
INNER JOIN departments d ON e.dept_id = d.id;
-- Oracle 전용 구문
SELECT e.name AS 직원명, d.name AS 부서명, e.salary
FROM employees e, departments d
WHERE e.dept_id = d.id;
LEFT OUTER JOIN
-- ANSI 표준 (권장)
SELECT e.name AS 직원명, d.name AS 부서명, e.salary
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.id;
-- Oracle 전용 구문 (+)
SELECT e.name AS 직원명, d.name AS 부서명, e.salary
FROM employees e, departments d
WHERE e.dept_id = d.id(+);
-- (+)는 데이터가 없을 수 있는 쪽에 붙입니다
+--------+--------+---------+
| 직원명 | 부서명 | SALARY |
+--------+--------+---------+
| 홍길동 | 개발팀 | 5000000 |
| 김철수 | 기획팀 | 4500000 |
| 이영희 | 개발팀 | 5500000 |
| 박민수 | 디자인팀 | 4800000 |
| 최지은 | (null) | 4000000 |
+--------+--------+---------+
매칭 안 되는 행만 조회
SELECT e.name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.id
WHERE d.id IS NULL;
RIGHT OUTER JOIN
-- ANSI 표준
SELECT e.name AS 직원명, d.name AS 부서명
FROM employees e
RIGHT JOIN departments d ON e.dept_id = d.id;
-- Oracle 전용 구문
SELECT e.name AS 직원명, d.name AS 부서명
FROM employees e, departments d
WHERE e.dept_id(+) = d.id;
FULL OUTER JOIN
양쪽 테이블의 모든 행을 반환합니다. Oracle 전용 (+) 구문으로는 표현할 수 없습니다.
SELECT e.name AS 직원명, d.name AS 부서명
FROM employees e
FULL OUTER JOIN departments d ON e.dept_id = d.id;
+--------+--------+
| 직원명 | 부서명 |
+--------+--------+
| 홍길동 | 개발팀 |
| 이영희 | 개발팀 |
| 김철수 | 기획팀 |
| 박민수 | 디자인팀 |
| 최지은 | (null) |
| (null) | 인사팀 |
+--------+--------+
CROSS JOIN
-- ANSI 표준
SELECT e.name, d.name
FROM employees e
CROSS JOIN departments d;
-- Oracle 전용 (FROM에 콤마로 나열, WHERE 없음)
SELECT e.name, d.name
FROM employees e, departments d;
-- 5명 × 4부서 = 20행
SELF JOIN
CREATE TABLE staff (
id NUMBER(10) PRIMARY KEY,
name VARCHAR2(50) NOT NULL,
manager_id NUMBER(10),
CONSTRAINT fk_staff_mgr FOREIGN KEY (manager_id) REFERENCES staff(id)
);
INSERT INTO staff VALUES (1, '김대표', NULL);
INSERT INTO staff VALUES (2, '이부장', 1);
INSERT INTO staff VALUES (3, '박과장', 2);
INSERT INTO staff VALUES (4, '최사원', 3);
COMMIT;
-- 직원과 상사 이름 함께 조회
SELECT s.name AS 직원, m.name AS 상사
FROM staff s
LEFT JOIN staff m ON s.manager_id = m.id;
NATURAL JOIN / USING
Oracle에서 지원하는 간결한 JOIN 구문입니다.
-- NATURAL JOIN: 동일한 컬럼명으로 자동 매칭
-- ⚠️ 의도치 않은 컬럼 매칭 위험이 있어 실무에서는 비권장
SELECT e.name, departments.name AS dept_name
FROM employees e
NATURAL JOIN departments;
-- USING: 매칭 컬럼 명시 (컬럼명이 동일할 때)
-- dept_id 대신 양쪽 모두 id라면:
SELECT e.name, d.name
FROM employees e
JOIN departments d USING (dept_id);
다중 테이블 JOIN
CREATE TABLE projects (
id NUMBER(10) PRIMARY KEY,
name VARCHAR2(100) NOT NULL,
dept_id NUMBER(10),
CONSTRAINT fk_proj_dept FOREIGN KEY (dept_id) REFERENCES departments(id)
);
-- 3개 테이블 결합
SELECT e.name AS 직원명, d.name AS 부서명, p.name AS 프로젝트명
FROM employees e
INNER JOIN departments d ON e.dept_id = d.id
INNER JOIN projects p ON d.id = p.dept_id;
-- Oracle 전용 구문
SELECT e.name AS 직원명, d.name AS 부서명, p.name AS 프로젝트명
FROM employees e, departments d, projects p
WHERE e.dept_id = d.id
AND d.id = p.dept_id;
JOIN 사용 시 주의사항
| 주의사항 | 설명 |
|---|---|
| (+) 구문 제한 | FULL OUTER JOIN 불가, OR 조건과 함께 사용 불가 |
| ANSI 표준 권장 | 가독성, 유지보수, 호환성 모두 우수 |
| 인덱스 확인 | JOIN 컬럼에 인덱스가 없으면 성능 저하 |
| 별칭 필수 | 컬럼명 중복 시 반드시 테이블 별칭 사용 |
-- ❌ (+) 구문의 한계: OR 조건 사용 불가
SELECT * FROM employees e, departments d
WHERE e.dept_id = d.id(+) OR e.name = d.name(+); -- 오류
-- ✅ ANSI 표준으로 해결
SELECT * FROM employees e
LEFT JOIN departments d ON e.dept_id = d.id OR e.name = d.name;
- [Oracle] 13. 자주 발생하는 Troubleshooting
- [Oracle] 12. 성능 튜닝 (Performance Tuning)
- [Oracle] 11. 백업과 복구 (Backup & Recovery)
- [Oracle] 10. 사용자 관리와 권한 (User & Privilege)
- [Oracle] 09. PL/SQL, 뷰, 프로시저, 트리거
- [Oracle] 08. 트랜잭션과 락 (Transaction & Lock)
- [Oracle] 07. 인덱스 (Index)
- [Oracle] 06. 내장 함수 정리
- [Oracle] 05. 서브쿼리와 고급 SELECT
- [Oracle] 04. JOIN (테이블 결합)
- [Oracle] 03. CRUD 기본 (INSERT, SELECT, UPDATE, DELETE)
- [Oracle] 02. 테이블스페이스와 테이블 관리
- [Oracle] 01. Oracle DB 소개 및 설치