AI와 개발을 쉽게 이해하는 실험실

비개발자도 따라오는 AI 도구, 자동화, 개발 실험 기록

개발 & 기술/데이터베이스

SQL JOIN 정리: INNER·LEFT·OUTER를 그림으로 이해하기

루민 Lumin 2026. 7. 26. 18:53
반응형

SQL JOIN 정리를 처음 배우는 분을 위해 INNER, LEFT, RIGHT, OUTER JOIN의 차이를 표와 그림으로 풀어냅니다. 어떤 상황에 어떤 JOIN을 써야 하는지 감이 잡히도록 예시 데이터와 함께 단계별로 설명합니다.

SQL JOIN 정리: INNER·LEFT·OUTER를 그림으로 이해하기의 핵심 개념을 단순한 테크 일러스트로 표현한 대표 이미지

SQL JOIN 정리를 검색하면 벤 다이어그램 하나만 툭 나와 있고 "그래서 언제 뭘 쓰라는 거지?" 싶을 때가 많습니다. 이 글은 두 개의 표를 붙이는 네 가지 방식(INNER·LEFT·RIGHT·FULL OUTER)에서 실제 데이터가 어떻게 남고 사라지는지 그림으로 보여드립니다. 처음엔 이름이 헷갈리지만, "어느 쪽 표를 다 살릴 거냐"만 정하면 나머지는 자동으로 풀립니다. 실무에서 빈 행(NULL)이 튀어나오는 이유도 함께 짚어드립니다.

JOIN이 필요한 순간

JOIN은 서로 다른 두 개의 표(테이블)를 공통된 열을 기준으로 옆으로 이어 붙이는 SQL 기능입니다.

예를 들어 쇼핑몰이라면 "회원 정보"와 "주문 내역"이 따로 저장되어 있습니다. 회원 표에는 이름·이메일이 있고, 주문 표에는 주문 번호·상품명이 있죠.

"홍길동이 뭘 샀지?"를 알려면 두 표를 회원 ID로 연결해야 합니다. 이때 쓰는 게 JOIN입니다.

💡 관계형 데이터베이스가 데이터를 여러 표에 나눠 저장하는 이유는 중복을 줄이기 위해서입니다. 대신 볼 때 붙여야 하는데, 그 붙이는 도구가 JOIN이죠.

예시 데이터부터 정하기

설명을 위해 아주 작은 두 개의 표를 쓰겠습니다. 회원 표와 주문 표입니다.

회원 (users)

user_id name
1 김철수
2 이영희
3 박민수

주문 (orders)

order_id user_id product
101 1 키보드
102 1 마우스
103 2 모니터
104 5 노트북

여기서 주목할 지점이 두 가지입니다.

  • 박민수(user_id=3)는 회원이지만 주문 기록이 없습니다.
  • 주문 104의 user_id=5는 회원 표에 없는 사용자입니다 (탈퇴했거나 데이터가 어긋난 경우).

이 두 개의 "짝 없는 행"이 JOIN 종류를 나누는 핵심입니다.

INNER JOIN: 양쪽 모두에 있는 것만

INNER JOIN은 두 표에서 공통으로 매칭되는 행만 남깁니다. 짝이 없는 행은 버립니다.

SELECT u.name, o.product
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;

이 쿼리는 "user_id가 양쪽에 다 있는 행만 골라서 이름과 상품을 보여줘"라는 뜻입니다.

결과

name product
김철수 키보드
김철수 마우스
이영희 모니터

박민수는 주문이 없어서 빠졌고, user_id=5의 노트북 주문도 회원 표에 매칭이 없어서 빠졌습니다.

그림으로 그리면 이렇게 됩니다.

회원      주문
[1] ─── [1,1]
[2] ─── [2]
[3]      [5]
 ↑        ↑
 짝 없음  짝 없음
 → 둘 다 결과에서 제외

언제 쓰나: "실제로 뭔가 산 회원의 구매 내역"처럼 양쪽 데이터가 반드시 매칭되어야 의미 있는 경우.

LEFT JOIN: 왼쪽 표는 환경에 따라 다 살림

LEFT JOIN은 왼쪽(FROM 뒤에 쓴) 표의 모든 행을 유지하고, 오른쪽에서 매칭되는 게 없으면 NULL로 채웁니다.

SELECT u.name, o.product
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;

결과

name product
김철수 키보드
김철수 마우스
이영희 모니터
박민수 NULL

박민수가 살아남았습니다. 주문이 없으니 product는 NULL(비어 있음)로 표시됩니다.

NULL은 "값이 없음"을 뜻하는 특수한 상태입니다. 숫자 0이나 빈 문자열과 다릅니다.

왼쪽 = users    오른쪽 = orders
[1] ────────── [1,1] 
[2] ────────── [2]
[3] ────────── NULL   ← 왼쪽은 살리고 오른쪽 없으면 NULL

언제 쓰나: "모든 회원 목록과, 있으면 최근 주문도 같이 보고 싶을 때". 회원 관리, 재고 조회, 출석부처럼 한쪽 기준을 다 보여줘야 하는 경우에 가장 많이 씁니다.

실무에서 가장 자주 등장하는 JOIN이 LEFT JOIN입니다.

RIGHT JOIN: 오른쪽 표를 다 살림

RIGHT JOIN은 LEFT JOIN을 뒤집은 것입니다. 오른쪽 표의 모든 행을 유지하고 왼쪽에서 없으면 NULL로 채웁니다.

SELECT u.name, o.product
FROM users u
RIGHT JOIN orders o ON u.user_id = o.user_id;

결과

name product
김철수 키보드
김철수 마우스
이영희 모니터
NULL 노트북

이번엔 user_id=5의 노트북 주문이 살아남았습니다. 회원 표에 매칭이 없으니 name이 NULL입니다.

실무에서는 RIGHT JOIN 대신 표의 순서를 바꿔서 LEFT JOIN으로 쓰는 경우가 많습니다. 읽기가 더 직관적이거든요. 결과는 똑같습니다.

FULL OUTER JOIN: 양쪽 다 살림

FULL OUTER JOIN은 양쪽 표의 모든 행을 다 유지하고, 매칭 안 되는 자리는 NULL로 채웁니다.

SELECT u.name, o.product
FROM users u
FULL OUTER JOIN orders o ON u.user_id = o.user_id;

결과

name product
김철수 키보드
김철수 마우스
이영희 모니터
박민수 NULL
NULL 노트북

박민수도, 노트북 주문도 모두 살아남았습니다.

주의할 점 하나. MySQL은 FULL OUTER JOIN을 직접 지원하지 않습니다. LEFT JOIN과 RIGHT JOIN의 결과를 UNION으로 합치는 우회 방법을 씁니다. PostgreSQL, SQL Server, Oracle에서는 그대로 됩니다. 정확한 문법은 사용하는 DB 공식 문서에서 확인하세요.

언제 쓰나: 두 표의 데이터가 서로 어긋난 부분까지 다 보고 싶을 때. 데이터 검증이나 마이그레이션 확인에 유용합니다.

한눈에 비교

네 가지 JOIN을 한 표로 정리하면 이렇습니다.

JOIN 종류 왼쪽 표 오른쪽 표 결과 특징
INNER 매칭된 것만 매칭된 것만 NULL 안 생김
LEFT 전부 유지 매칭된 것만 오른쪽에 NULL 생길 수 있음
RIGHT 매칭된 것만 전부 유지 왼쪽에 NULL 생길 수 있음
FULL OUTER 전부 유지 전부 유지 양쪽에 NULL 생길 수 있음

선택 기준을 흐름도로 그리면 이렇습니다.

"어느 쪽 표를 다 보여줄까?"
        │
   ┌────┴────┬──────┐
   ▼         ▼      ▼
 양쪽 다   한쪽만   매칭된
 필요     기준     것만
   │        │       │
FULL     LEFT     INNER
OUTER   (또는
        RIGHT)

자주 막히는 부분

입문 단계에서 반복적으로 나오는 함정들입니다.

1. INNER JOIN인데 결과가 예상보다 적다

양쪽 표에 매칭되는 행이 생각보다 적기 때문입니다. 특히 한쪽 표에 데이터 입력 실수(오타·공백·대소문자 차이)가 있으면 매칭이 안 됩니다. LEFT JOIN으로 바꿔서 NULL이 어디서 튀어나오는지 확인하면 원인을 찾기 좋습니다.

2. LEFT JOIN 후 WHERE 조건에서 NULL 행이 사라진다

SELECT u.name, o.product
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.product = '키보드';

이렇게 쓰면 박민수(주문 없음)는 결과에서 빠집니다. WHERE 절이 NULL도 걸러내기 때문이죠. NULL을 남기려면 조건을 ON 절에 넣거나 OR o.product IS NULL을 추가해야 합니다.

3. JOIN을 여러 번 걸었더니 행 수가 폭발한다

한 회원에게 주문이 10개, 각 주문에 상품이 3개씩이면 결과는 30행이 됩니다. 이걸 카티션 곱(cartesian product) 비슷한 현상이라고 하는데, 실무에서 집계(SUM, COUNT)를 하기 전에 어느 단위로 행이 늘어나는지 먼저 파악해야 숫자가 맞습니다.

다음에 해보면 좋을 것

JOIN은 눈으로 보는 것과 손으로 쳐보는 것 차이가 큽니다. 개념이 대충 잡혔다면 다음 순서로 익혀보세요.

  • SQLite나 온라인 SQL 연습 사이트에서 위 예시 데이터를 직접 만들어 4가지 JOIN을 돌려보기
  • LEFT JOIN + WHERE IS NULL로 "주문 없는 회원 찾기" 쿼리 짜보기
  • 3개 이상의 표를 연결해보기 (회원 - 주문 - 상품 카테고리 순으로)
  • 사용하는 DB의 공식 문서에서 JOIN 문법 페이지 한 번 훑기 (문법 세부사항이 DB마다 조금씩 다릅니다)

결국 JOIN은 "어느 쪽 표를 기준으로 세울 것인가"를 정하는 일입니다. 그 감이 잡히면 SELECT 문의 절반은 이미 익힌 셈이죠.

함께 보면 좋은 글

반응형