1. SQL - JOIN (#1)

Jason·2026년 1월 12일

SQL

목록 보기
1/47
post-thumbnail

INNER, LEFT, RIGHT

SQL JOIN 완벽 정리 — 테이블 연결의 모든 것

💡 SQL에서 가장 중요한 개념 중 하나인 JOIN을 완벽하게 정리한다.


🤔 JOIN이 뭐야?

두 개 이상의 테이블을 연결해서 데이터를 가져오는 것.

현실에서 데이터는 여러 테이블에 나뉘어 저장된다:

  • users 테이블: 유저 정보
  • orders 테이블: 주문 정보
  • products 테이블: 상품 정보

→ "어떤 유저가 어떤 상품을 샀는지" 알려면? JOIN 필요!


📊 예제 테이블

이 글에서 사용할 테이블:

[users]
| user_id | name |
|---------|------|
| 1 | 김철수 |
| 2 | 이영희 |
| 3 | 박민수 |
| 4 | 최지은 |

[orders]
| order_id | user_id | product | amount |
|----------|---------|---------|--------|
| 101 | 1 | 노트북 | 1500000 |
| 102 | 1 | 마우스 | 50000 |
| 103 | 2 | 키보드 | 100000 |
| 104 | 5 | 모니터 | 300000 |

포인트:

  • user_id 3, 4는 주문 없음
  • order_id 104의 user_id 5는 users에 없음

.
.
.
.
.
.
.


🔗 JOIN 종류 한눈에

[INNER JOIN]  — 양쪽 다 있는 것만
[LEFT JOIN]   — 왼쪽 전부 + 매칭되는 오른쪽
[RIGHT JOIN]  — 오른쪽 전부 + 매칭되는 왼쪽
[FULL JOIN]   — 양쪽 전부 (합집합)
[CROSS JOIN]  — 모든 조합 (곱집합)

1️⃣ INNER JOIN

개념

양쪽 테이블에 모두 존재하는 데이터만 가져온다.

[users]     [orders]
   1  ────────  1
   2  ────────  2
   3            5
   4
   
→ 결과: 1, 2만 (교집합)

문법

SELECT *
FROM users u
INNER JOIN orders o ON u.user_id = o.user_id;

또는 줄여서:

SELECT *
FROM users u
JOIN orders o ON u.user_id = o.user_id;

INNER는 생략 가능! JOIN만 쓰면 기본이 INNER JOIN

결과

user_idnameorder_idproductamount
1김철수101노트북1500000
1김철수102마우스50000
2이영희103키보드100000

사라진 것:

  • 박민수, 최지은 (주문 없음)
  • order_id 104 (user_id 5가 users에 없음)

언제 쓰나?

  • "매칭되는 데이터만" 필요할 때
  • 양쪽 다 있는 게 확실할 때

2️⃣ LEFT JOIN

개념

왼쪽 테이블은 전부 가져오고, 오른쪽은 매칭되는 것만.

[users]     [orders]
   1  ────────  1
   2  ────────  2
   3  ──→ NULL
   4  ──→ NULL
   
→ 결과: 1, 2, 3, 4 (왼쪽 전부)

문법

SELECT *
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id;

결과

user_idnameorder_idproductamount
1김철수101노트북1500000
1김철수102마우스50000
2이영희103키보드100000
3박민수NULLNULLNULL
4최지은NULLNULLNULL

포인트: 주문 없는 유저도 나옴! (NULL로 채워짐)

언제 쓰나?

  • "주문 안 한 유저도 보고 싶다"
  • 왼쪽 테이블 기준으로 전체 현황 파악

💡 실전 활용: 주문 안 한 유저 찾기

SELECT u.user_id, u.name
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;
user_idname
3박민수
4최지은

LEFT JOIN + WHERE NULL 패턴 자주 나옴!


3️⃣ RIGHT JOIN

개념

LEFT JOIN의 반대. 오른쪽 테이블 전부 + 왼쪽 매칭.

[users]     [orders]
   1  ────────  1
   2  ────────  2
              NULL ←── 5
   
→ 결과: 1, 2, 5 (오른쪽 전부)

문법

SELECT *
FROM users u
RIGHT JOIN orders o ON u.user_id = o.user_id;

결과

user_idnameorder_idproductamount
1김철수101노트북1500000
1김철수102마우스50000
2이영희103키보드100000
NULLNULL104모니터300000

언제 쓰나?

실무에서 거의 안 씀! LEFT JOIN으로 테이블 순서만 바꾸면 됨.

-- 이것과
SELECT * FROM A RIGHT JOIN B ON ...

-- 이건 같은 결과
SELECT * FROM B LEFT JOIN A ON ...

LEFT JOIN만 잘 쓰면 됨


4️⃣ FULL OUTER JOIN

개념

양쪽 테이블 전부 가져온다. (합집합)

[users]     [orders]
   1  ────────  1
   2  ────────  2
   3  ──→ NULL
   4  ──→ NULL
              NULL ←── 5
   
→ 결과: 1, 2, 3, 4, 5 (전부)

문법

SELECT *
FROM users u
FULL OUTER JOIN orders o ON u.user_id = o.user_id;

결과

user_idnameorder_idproductamount
1김철수101노트북1500000
1김철수102마우스50000
2이영희103키보드100000
3박민수NULLNULLNULL
4최지은NULLNULLNULL
NULLNULL104모니터300000

주의

  • MySQL은 FULL OUTER JOIN 지원 안 함!
  • PostgreSQL, SQL Server 등에서 사용 가능

MySQL에서 구현하려면:

SELECT * FROM users u LEFT JOIN orders o ON u.user_id = o.user_id
UNION
SELECT * FROM users u RIGHT JOIN orders o ON u.user_id = o.user_id;

5️⃣ CROSS JOIN

개념

모든 조합을 만든다. (곱집합)

users 4행 × orders 4행 = 16행

문법

SELECT *
FROM users
CROSS JOIN orders;

또는:

SELECT *
FROM users, orders;

언제 쓰나?

  • 모든 조합이 필요할 때
  • 달력 데이터 생성
  • 테스트 데이터 생성

예: 모든 날짜 × 모든 상품 조합

SELECT d.date, p.product_name
FROM dates d
CROSS JOIN products p;

📝 JOIN 비교 요약

JOIN 종류결과쉬운 설명
INNER교집합둘 다 있는 것만
LEFT왼쪽 전부왼쪽 기준
RIGHT오른쪽 전부(거의 안 씀)
FULL합집합다 가져와
CROSS곱집합모든 조합

실무 빈도:

INNER JOIN ████████████ 40%
LEFT JOIN  ████████████████ 55%
나머지     ██ 5%

INNER, LEFT만 확실히 알면 90% 커버!


🎯 실전 문제

문제 1: 기본 JOIN

모든 주문에 대해 주문자 이름과 상품명, 금액을 조회하세요.

정답 보기
SELECT u.name, o.product, o.amount
FROM orders o
JOIN users u ON o.user_id = u.user_id;

문제 2: LEFT JOIN

모든 유저의 총 주문 금액을 구하세요. 주문이 없는 유저는 0으로 표시.

정답 보기
SELECT 
    u.name,
    COALESCE(SUM(o.amount), 0) AS total_amount
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
GROUP BY u.user_id, u.name;
nametotal_amount
김철수1550000
이영희100000
박민수0
최지은0

포인트: COALESCE로 NULL을 0으로 변환!


문제 3: 주문 없는 유저 찾기

한 번도 주문하지 않은 유저를 찾으세요.

정답 보기
SELECT u.user_id, u.name
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.order_id IS NULL;

💡 JOIN 팁

1. ON 조건 vs WHERE 조건

-- ON에 조건 (JOIN 전에 필터링)
SELECT *
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id 
                   AND o.amount > 100000;

-- WHERE에 조건 (JOIN 후에 필터링)
SELECT *
FROM users u
LEFT JOIN orders o ON u.user_id = o.user_id
WHERE o.amount > 100000;

LEFT JOIN에서 결과가 다를 수 있음! 주의!

2. 테이블 별칭(Alias) 활용

-- 길게
SELECT users.name, orders.product
FROM users
JOIN orders ON users.user_id = orders.user_id;

-- 짧게 (권장)
SELECT u.name, o.product
FROM users u
JOIN orders o ON u.user_id = o.user_id;

3. 여러 테이블 JOIN

SELECT 
    u.name,
    o.order_id,
    p.product_name,
    p.price
FROM users u
JOIN orders o ON u.user_id = o.user_id
JOIN products p ON o.product_id = p.product_id;

→ 체인처럼 연결!


🔗 다음 포스트

[SQL 시리즈 #2] GROUP BY & 집계함수 — 데이터 요약의 기술


📝 JOIN은 SQL의 핵심이다.
INNER JOIN과 LEFT JOIN만 확실히 이해해도 대부분의 상황에 대응할 수 있다.
실전에서는 "어느 테이블을 기준으로 할 것인가"를 먼저 생각하자!

profile
Data Analyst | Thoughts Become Things. 할 수 있다고 생각하면 할 수 있다. 할 수 없다고 생각하면 할 수 없다. | www.linkedin.com/in/명수-제-7ab843200

0개의 댓글