SQLSQL 기초 · 3입문

JOIN — 여러 테이블 연결하기

SQLJOININNER JOINLEFT JOIN외래키

왜 여러 테이블인가?

데이터 중복을 줄이기 위해 관련 데이터를 별도 테이블로 분리합니다.

-- 주문 테이블에 고객 정보를 중복 저장하지 않음
CREATE TABLE customers (
    id    SERIAL PRIMARY KEY,
    name  VARCHAR(100),
    email VARCHAR(200)
);

CREATE TABLE orders (
    id          SERIAL PRIMARY KEY,
    customer_id INTEGER REFERENCES customers(id),  -- 외래키
    amount      INTEGER,
    created_at  TIMESTAMP DEFAULT NOW()
);

INNER JOIN

두 테이블 모두에 일치하는 행만 반환합니다.

SELECT
    orders.id AS order_id,
    customers.name,
    orders.amount
FROM orders
INNER JOIN customers ON orders.customer_id = customers.id;

-- 결과 (일치하는 행만)
-- order_id | name | amount
-- ---------|------|-------
-- 1        | 철수  | 50000
-- 2        | 영희  | 30000

LEFT JOIN

왼쪽(FROM) 테이블의 모든 행 + 오른쪽에서 일치하는 행.

-- 주문 없는 고객도 포함
SELECT
    customers.name,
    orders.id AS order_id,
    orders.amount
FROM customers
LEFT JOIN orders ON customers.id = orders.customer_id;

-- 결과
-- name | order_id | amount
-- -----|----------|-------
-- 철수  | 1        | 50000
-- 영희  | 2        | 30000
-- 민준  | NULL     | NULL   ← 주문 없는 고객

JOIN 시각화

flowchart LR
    subgraph INNER["INNER JOIN"]
        A1["A"]
        B1["B"]
        AB1["A ∩ B\n일치하는 행"]
    end
    subgraph LEFT["LEFT JOIN"]
        A2["A (전체)"]
        B2["B (일치만)"]
    end
    subgraph RIGHT["RIGHT JOIN"]
        A3["A (일치만)"]
        B3["B (전체)"]
    end
    subgraph FULL["FULL OUTER JOIN"]
        A4["A (전체)"]
        B4["B (전체)"]
    end

별칭(Alias)으로 가독성 향상

-- 테이블 별칭
SELECT
    c.name,
    o.id AS order_id,
    o.amount
FROM customers AS c
INNER JOIN orders AS o ON c.id = o.customer_id
WHERE o.amount > 30000;

-- 더 짧게 (AS 생략 가능)
SELECT c.name, o.id, o.amount
FROM customers c
JOIN orders o ON c.id = o.customer_id;

3개 이상 테이블 JOIN

-- customers → orders → products 조인
SELECT
    c.name AS customer,
    p.name AS product,
    oi.quantity,
    p.price * oi.quantity AS total
FROM customers c
JOIN orders o ON c.id = o.customer_id
JOIN order_items oi ON o.id = oi.order_id
JOIN products p ON oi.product_id = p.id
WHERE c.id = 1;

자기 참조 JOIN (Self Join)

같은 테이블을 두 번 JOIN합니다.

-- 직원과 그 직원의 매니저 (둘 다 employees 테이블)
CREATE TABLE employees (
    id         SERIAL PRIMARY KEY,
    name       VARCHAR(100),
    manager_id INTEGER REFERENCES employees(id)  -- 자기 참조
);

SELECT
    e.name AS employee,
    m.name AS manager
FROM employees e
LEFT JOIN employees m ON e.manager_id = m.id;

NULL 처리와 JOIN

-- LEFT JOIN에서 일치 없는 행 찾기 (NOT IN 대안)
SELECT c.name
FROM customers c
LEFT JOIN orders o ON c.id = o.customer_id
WHERE o.id IS NULL;  -- 주문이 없는 고객만

정리

JOIN반환하는 행
INNER JOIN양쪽 모두 일치
LEFT JOIN왼쪽 전체 + 오른쪽 일치
RIGHT JOIN오른쪽 전체 + 왼쪽 일치
FULL OUTER JOIN양쪽 전체 (일치 안 해도)
CROSS JOIN모든 조합 (카테시안 곱)

다음 편에서는 집계 함수와 GROUP BY — 데이터를 그룹화해 통계를 계산하는 방법을 배웁니다.

궁금한 점이 있으신가요?

협업·의뢰는 아래로, 가벼운 소통은 인스타그램 @bluefox._.hi도 환영이에요.