상상해봐, 네가 학생 목록이랑 그 학생들이 수강 신청한 강좌 목록, 이렇게 두 개의 테이블을 가지고 있다고 해. 모든 학생이 강좌를 신청한 건 아니고, 아직 아무 강좌도 고르지 않은 학생도 있을 수 있어. 모든 학생을 다 보고 싶은데, 누가 어떤 강좌를 들었는지도 같이 보고 싶어. INNER JOIN을 쓰면 강좌를 신청한 학생만 나오는데, 나머지 학생들은 어떻게 하지? 이럴 때 LEFT JOIN이 딱이야.
LEFT JOIN은 왼쪽 테이블의 모든 행(쿼리에서 먼저 지정한 테이블)과 오른쪽 테이블에서 매칭되는 행을 반환해. 만약 매칭되는 게 없으면 오른쪽 테이블의 컬럼에는 NULL이 들어가.
LEFT JOIN 문법
SELECT
테이블1.컬럼1,
테이블1.컬럼2,
테이블2.컬럼1,
테이블2.컬럼2
FROM
테이블1 LEFT JOIN 테이블2
ON
테이블1.공통_컬럼 = 테이블2.공통_컬럼;
테이블1— "왼쪽" 테이블이야.테이블2— "오른쪽" 테이블이야.공통_컬럼— 조인할 때 기준이 되는 컬럼이야.
예시로 쉽게 설명해볼게
만약 students 테이블이 이렇게 생겼다고 해:
| student_id | name |
|---|---|
| 1 | Otto |
| 2 | Anna |
| 3 | Peter |
그리고 enrollments 테이블은 이렇게 생겼어:
| enrollment_id | student_id | course |
|---|---|---|
| 1 | 1 | 수학 |
| 2 | 1 | 물리 |
| 3 | 2 | 생물 |
이제 쿼리를 이렇게 짜면:
SELECT
students.name,
enrollments.course
FROM
students LEFT JOIN enrollments
ON
students.student_id = enrollments.student_id;
결과는 이렇게 나와:
| name | course |
|---|---|
| Otto | 수학 |
| Otto | 물리 |
| Anna | 생물 |
| Peter | NULL |
보다시피, 결과에는 모든 학생이 남아있지. 아직 아무 강좌도 신청 안 한 Peter도 포함돼. Peter의 course 컬럼에는 NULL이 들어가 있어.
LEFT JOIN 활용 예시
예시 1: 모든 학생과 그들의 강좌 리스트 가져오기
이런 상황을 생각해봐: 모든 학생과, 그 학생이 신청한 강좌(있으면)까지 한 번에 보고 싶어. 만약 아직 강좌를 고르지 않았다면 그것도 표시되어야 해.
아까 썼던 쿼리랑 똑같아:
SELECT
students.name,
enrollments.course
FROM
students LEFT JOIN enrollments
ON
students.student_id = enrollments.student_id;
결과:
| name | course |
|---|---|
| Otto | 수학 |
| Otto | 물리 |
| Anna | 생물 |
| Peter | NULL |
이게 바로 LEFT JOIN의 대표적인 예시야.
예시 2: 상품과 그 판매량 출력하기
이번엔 두 개의 테이블이 있다고 해보자:
모든 상품이 들어있는 products 테이블:
| product_id | product_name |
|---|---|
| 1 | 스마트폰 |
| 2 | 태블릿 |
| 3 | 노트북 |
판매 데이터를 담고 있는 sales 테이블:
| sale_id | product_id | quantity |
|---|---|---|
| 1 | 1 | 5 |
| 2 | 1 | 3 |
| 3 | 2 | 2 |
이제 모든 상품과, 아직 한 번도 팔리지 않은 상품까지 포함해서 판매량을 보고 싶어.
SELECT
products.product_name,
SUM(sales.quantity) AS total_sold
FROM
products LEFT JOIN sales
ON
products.product_id = sales.product_id
GROUP BY
products.product_name;
결과:
| product_name | total_sold |
|---|---|
| 스마트폰 | 8 |
| 태블릿 | 2 |
| 노트북 | NULL |
LEFT JOIN 쓸 때 주의할 점
NULL이 항상 필요한 건 아니야?
가끔 LEFT JOIN을 쓰면 예상치 못한 곳에 NULL이 들어가기도 해. 이럴 땐 COALESCE() 함수로 NULL 대신 더 알아보기 쉬운 값으로 바꿔줄 수 있어.
SELECT
students.name,
COALESCE(enrollments.course, '강좌 선택 안 함') AS course
FROM
students LEFT JOIN enrollments
ON
students.student_id = enrollments.student_id;
결과:
| name | course |
|---|---|
| Otto | 수학 |
| Otto | 물리 |
| Anna | 생물 |
| Peter | 강좌 선택 안 함 |
불필요한 중복
만약 오른쪽 테이블에 중복된 데이터가 있으면, 쿼리 결과가 생각보다 더 많은 행을 반환할 수 있어. 데이터 상태를 잘 확인하고, 중복이 필요 없으면 DISTINCT를 써줘.
GO TO FULL VERSION