🧩 SQL 고급 SELECT & JOIN 완벽 가이드 (Oracle 기준)
데이터 분석과 실무에 꼭 필요한 JOIN 심화 설명 + 예시 🚀
🎯 목차
- JOIN이란? 왜 사용할까?
- JOIN의 종류와 사용법
- 다양한 JOIN 실전 예제
- 서브쿼리 vs JOIN 성능 비교
- 실무에서 JOIN 잘 쓰는 팁 💡
📝 1. JOIN이란? 왜 사용할까?
데이터베이스에서 JOIN은 여러 테이블에 흩어져 있는 데이터를 "합쳐서" 하나로 보여줍니다.
✅ 왜 필요할까?
- 테이블은 보통 중복을 줄이기 위해 나누어져 있습니다.
- 필요한 정보가 서로 다른 테이블에 있을 때 JOIN으로 결합합니다.
🔍 예시 상황:
- employees 테이블: 직원 정보
- departments 테이블: 부서 정보
➡️ "직원이 속한 부서명을 알고 싶다" 👉 두 테이블 JOIN 필요!
🔗 2. JOIN의 종류와 사용법
🌱 2.1 INNER JOIN (교집합)
- 양쪽 테이블에 공통된 값이 있을 때만 결과를 반환합니다.
- 실무에서 가장 자주 사용합니다.
SELECT e.employee_id, e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id;
✅ 설명: 직원 테이블(employees)과 부서 테이블(departments)을 부서 ID 기준으로 연결.
✅ 결과: 부서가 있는 직원만 조회됩니다.
🍀 2.2 LEFT JOIN (LEFT OUTER JOIN) - 왼쪽 테이블 중심
- 왼쪽 테이블은 모두 가져오고, 오른쪽 테이블에 값이 없으면 NULL 반환.
- "모든 직원과 (부서가 없어도) 그들의 부서 정보"를 보고 싶을 때 유용합니다.
SELECT e.employee_id, e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;
✅ 결과: 부서가 없는 직원도 조회 (부서명은 NULL)
🌸 2.3 RIGHT JOIN (RIGHT OUTER JOIN) - 오른쪽 테이블 중심
- 오른쪽 테이블은 모두 가져오고, 왼쪽 테이블에 값이 없으면 NULL 반환.
- "모든 부서와 그 부서에 소속된 직원들"을 볼 때 사용.
SELECT e.employee_id, e.name, d.department_name
FROM employees e
RIGHT JOIN departments d ON e.department_id = d.department_id;
✅ 결과: 직원이 없는 부서도 표시됨.
🌎 2.4 FULL JOIN (FULL OUTER JOIN) - 전체 데이터 포함
- 양쪽 테이블 모든 데이터 포함. 공통 값이 없으면 NULL 채움.
- Oracle에서는 FULL JOIN 지원합니다.
SELECT e.employee_id, e.name, d.department_name
FROM employees e
FULL JOIN departments d ON e.department_id = d.department_id;
✅ 결과: 직원이 없는 부서 + 부서가 없는 직원 모두 표시됩니다.
🌳 2.5 SELF JOIN - 자기 자신과 JOIN
- 같은 테이블 내에서 관계 찾을 때 사용
- 예시: 직원 중 "누가 누구의 상사인지" 알고 싶을 때
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.employee_id;
✅ 결과: 각 직원과 그들의 매니저 이름 표시
🧪 3. 다양한 JOIN 실전 예제
🎯 예제 데이터
▶️ employees 테이블:
employee_id | name | department_id | manager_id |
1 | Alice | 10 | NULL |
2 | Bob | 20 | 1 |
3 | Charlie | 10 | 1 |
4 | David | NULL | 2 |
▶️ departments 테이블:
department_id | department_name |
10 | HR |
20 | IT |
30 | Sales |
🔎 3.1 INNER JOIN 예제
SELECT e.name, d.department_name
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id;
결과:
name | department_name |
Alice | HR |
Bob | IT |
Charlie | HR |
➡️ David는 department_id가 없어서 제외됨.
🌱 3.2 LEFT JOIN 예제
SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id;
결과:
name | department_name |
Alice | HR |
Bob | IT |
Charlie | HR |
David | NULL |
➡️ David도 결과에 포함되지만 부서가 없으니 NULL 표시.
🌳 3.3 SELF JOIN 예제 (직원-매니저 관계)
SELECT e.name AS employee, m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.employee_id;
결과:
employee | manager |
Alice | NULL |
Bob | Alice |
Charlie | Alice |
David | Bob |
➡️ SELF JOIN으로 같은 테이블에서 관계 파악 가능.
⚡ 4. 서브쿼리 vs JOIN 성능 비교
✅ JOIN이 더 빠를 때:
- 테이블 간 관계가 명확할 때 (특히 큰 테이블에서)
- 인덱스가 잘 설정된 경우
🐢 서브쿼리가 느릴 때:
- 동일한 데이터를 여러 번 조회할 때
- 뷰(View) 안에서 서브쿼리 중첩 사용 시 성능 저하 가능
💡 일반 팁: 가능하면 JOIN을 우선 사용하고, 성능 문제 시 실행 계획을 분석하세요!
-- 서브쿼리 예시 (느릴 수 있음)
SELECT name
FROM employees
WHERE department_id = (
SELECT department_id FROM departments WHERE department_name = 'HR'
);
-- JOIN 예시 (더 빠름)
SELECT e.name
FROM employees e
JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = 'HR';
🧠 5. 실무에서 JOIN 잘 쓰는 팁 💡
✅ 항상 ON 조건을 명확히 적기! (잘못하면 CROSS JOIN으로 대참사😱)
✅ 테이블 별칭 사용으로 쿼리 가독성 높이기
✅ 불필요한 컬럼 제거로 성능 개선
✅ JOIN 전에 데이터 양 확인으로 속도 최적화
✅ LEFT JOIN 시 조건을 WHERE에 넣지 않기 (NULL 제거 방지)
LEFT JOIN 시 조건을 WHERE에 넣으면 LEFT JOIN의 본래 목적이 손상될 수 있습니다.
LEFT JOIN은 왼쪽 테이블의 모든 데이터를 유지하면서 오른쪽 테이블의 관련 데이터를 가져옵니다. 하지만 조건을 WHERE 절에 넣으면 NULL 값도 필터링되어, 사실상 INNER JOIN처럼 동작합니다.
🔍 예시
-- 잘못된 예시 (WHERE 사용 시 LEFT JOIN 의미 사라짐)
SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id
WHERE d.department_name = 'HR';
-- 올바른 예시 (ON 절에 조건 추가)
SELECT e.name, d.department_name
FROM employees e
LEFT JOIN departments d ON e.department_id = d.department_id AND d.department_name = 'HR';
결과 차이:
- WHERE 사용 시: 'HR'에 속한 직원만 조회 (부서 없는 직원 제외)
- ON 사용 시: 모든 직원 조회 + HR 부서 직원만 부서명 표시 (부서 없는 직원은 NULL)
👉 실무에서는 LEFT JOIN 본연의 목적(모든 왼쪽 테이블 데이터 유지)을 위해 조건을 ON 절에 넣으세요! 😊