개발/SQL

🧩 SQL 고급 SELECT & JOIN 완벽 가이드 (Oracle 기준)

예니03 2025. 2. 25. 08:35
반응형

데이터 분석과 실무에 꼭 필요한 JOIN 심화 설명 + 예시 🚀

🎯 목차

  1. JOIN이란? 왜 사용할까?
  2. JOIN의 종류와 사용법
  3. 다양한 JOIN 실전 예제
  4. 서브쿼리 vs JOIN 성능 비교
  5. 실무에서 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 절에 넣으세요! 😊

 

 

반응형