JOIN

mskimdev·2026년 4월 17일

MySQL

목록 보기
14/20
post-thumbnail

JOIN

테이블을 잘 나눠뒀는데, 막상 데이터를 꺼내려고 하면 문제가 생긴다. 주문 목록을 보고 싶은데 주문 테이블엔 member_id만 있고 이름은 없다. 회원 이름까지 같이 보려면 두 테이블을 합쳐서 조회해야 한다. 이때 쓰는 게 JOIN이다.


예시 데이터

설명에 사용할 테이블과 데이터를 먼저 준비한다.

-- 회원 테이블
INSERT INTO members VALUES
(1, '김민수', 'kim@email.com'),
(2, '이지현', 'lee@email.com'),
(3, '박준혁', 'park@email.com');  -- 주문 없는 회원

-- 주문 테이블
INSERT INTO orders VALUES
(1, 1, '2026-03-01'),
(2, 1, '2026-03-05'),
(3, 2, '2026-03-07'),
(4, 99, '2026-03-10');  -- 존재하지 않는 member_id
members                          orders
member_id | member_name          order_id | member_id | order_date
----------+------------          ---------+-----------+-----------
        1 | 김민수                       1 |         1 | 2026-03-01
        2 | 이지현                       2 |         1 | 2026-03-05
        3 | 박준혁                       3 |         2 | 2026-03-07
                                         4 |        99 | 2026-03-10

박준혁은 주문이 없고, order_id = 4는 존재하지 않는 회원의 주문이다. JOIN 종류마다 이 데이터가 어떻게 다르게 나오는지 비교하면 이해가 빠르다.


JOIN의 종류

INNER JOIN

두 테이블 모두에 존재하는 행만 결과에 포함된다. 매칭되는 데이터가 없으면 결과에서 빠진다.

SELECT m.member_name, o.order_id, o.order_date
FROM members m
INNER JOIN orders o ON m.member_id = o.member_id;
member_name | order_id | order_date
------------+----------+-----------
김민수       |        1 | 2026-03-01
김민수       |        2 | 2026-03-05
이지현       |        3 | 2026-03-07

박준혁은 주문이 없어서 결과에 없다. member_id = 99인 주문도 members에 없는 회원이라 빠진다. 양쪽 다 존재하는 것만 남긴다.

LEFT JOIN

왼쪽 테이블의 모든 행을 기준으로 오른쪽 테이블을 합친다. 오른쪽에 매칭되는 데이터가 없으면 NULL로 채운다.

SELECT m.member_name, o.order_id, o.order_date
FROM members m
LEFT JOIN orders o ON m.member_id = o.member_id;
member_name | order_id | order_date
------------+----------+-----------
김민수       |        1 | 2026-03-01
김민수       |        2 | 2026-03-05
이지현       |        3 | 2026-03-07
박준혁       |     NULL | NULL

박준혁은 주문이 없지만 왼쪽(members)에 있으니 결과에 포함된다. 주문 관련 컬럼은 NULL이다. "주문을 한 번도 안 한 회원을 찾아라" 같은 상황에서 유용하다.

-- 주문이 없는 회원만 조회
SELECT m.member_name
FROM members m
LEFT JOIN orders o ON m.member_id = o.member_id
WHERE o.order_id IS NULL;
member_name
-----------
박준혁

RIGHT JOIN

LEFT JOIN의 반대다. 오른쪽 테이블의 모든 행을 기준으로 왼쪽을 합친다. 왼쪽에 매칭되는 데이터가 없으면 NULL로 채운다.

SELECT m.member_name, o.order_id, o.order_date
FROM members m
RIGHT JOIN orders o ON m.member_id = o.member_id;
member_name | order_id | order_date
------------+----------+-----------
김민수       |        1 | 2026-03-01
김민수       |        2 | 2026-03-05
이지현       |        3 | 2026-03-07
NULL         |        4 | 2026-03-10

member_id = 99인 주문은 members에 없는 회원이지만 오른쪽(orders)에 있으니 포함된다. 회원 이름은 NULL이다.

현실적으로 LEFT JOIN이 훨씬 많이 쓰인다. FROM 뒤에 기준 테이블을 두고 LEFT JOIN으로 붙이는 방식이 읽기 쉽기 때문에, RIGHT JOIN이 필요한 상황은 대부분 테이블 순서를 바꿔서 LEFT JOIN으로 대체한다.


여러 테이블 JOIN

JOIN은 두 테이블 이상도 이어 붙일 수 있다. 주문에 상품명까지 함께 보고 싶다면 order_items, products까지 연결한다.

SELECT
    m.member_name,
    o.order_date,
    p.product_name,
    oi.quantity
FROM orders o
INNER JOIN members     m  ON o.member_id   = m.member_id
INNER JOIN order_items oi ON o.order_id    = oi.order_id
INNER JOIN products    p  ON oi.product_id = p.product_id;
member_name | order_date  | product_name  | quantity
------------+-------------+---------------+---------
김민수       | 2026-03-01  | 무선 마우스    |        2
김민수       | 2026-03-05  | 기계식 키보드  |        1
이지현       | 2026-03-07  | 기계식 키보드  |        1

FROM 뒤에 기준 테이블을 두고, JOIN을 이어 붙이는 방식이다. ON 조건만 정확히 맞춰주면 몇 개든 연결할 수 있다.


JOIN 종류 비교

JOIN포함되는 행
INNER JOIN양쪽 모두 매칭되는 행만
LEFT JOIN왼쪽 테이블 전체 + 오른쪽 매칭 (없으면 NULL)
RIGHT JOIN오른쪽 테이블 전체 + 왼쪽 매칭 (없으면 NULL)

JOIN을 처음 쓸 때 가장 헷갈리는 부분은 "어느 쪽이 기준이냐"다. LEFT, RIGHT는 방향이 아니라 어느 테이블의 행을 모두 살릴 건가의 문제다. 이걸 기준으로 생각하면 선택이 쉬워진다.

profile
<- 개발 공부하는 나

0개의 댓글