왜 여러 테이블인가?
데이터 중복을 줄이기 위해 관련 데이터를 별도 테이블로 분리합니다.
-- 주문 테이블에 고객 정보를 중복 저장하지 않음
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 — 데이터를 그룹화해 통계를 계산하는 방법을 배웁니다.