현재 테이블 구조는 의도적으로 정규화되어 있다. 즉, 데이터가 중복되지 않도록 테이블이 나뉘어져 있음.
| 테이블 | 역할 |
|---|---|
| customers | 고객 정보 |
| products | 상품 정보 |
| orders | 주문(누가 언제 주문했는지) |
| order_items | 주문에 포함된 상품 |
| payments | 결제 정보 |
예를 들어:
“누가 무엇을 얼마에 주문했는가?”
이 질문은 단일 테이블로는 절대 답할 수 없다.
👉 그래서 JOIN이 필요하다.
SELECT 컬럼들
FROM 테이블A a
JOIN 테이블B b ON a.공통컬럼 = b.공통컬럼;
“주문 목록에 고객 이름을 같이 보고 싶다”
SELECT
o.order_id,
o.ordered_at,
o.status,
o.total_amount,
c.name AS customer_name
FROM orders o
(INNER )JOIN customers c
ON o.customer_id = c.customer_id;
SELECT
o.order_id,
o.ordered_at,
o.status,
o.total_amount,
c.name AS customer_name
FROM orders o, customers c
WHERE o.customer_id = c.customer_id;
select
o.order_id,
c.name as customer_name,
o.status,
o.ordered_at
from orders o
join customers c
on o.customer_id = c.customer_id
“주문 하나에 어떤 상품들이 들어 있는가?”
SELECT
o.order_id,
oi.product_id,
oi.quantity,
oi.unit_price,
oi.line_amount
FROM orders o
JOIN order_items oi
ON o.order_id = oi.order_id;
SELECT
p.name,
oi.quantity,
oi.unit_price,
oi.line_amount
FROM products p
JOIN order_items oi
ON p.product_id = oi.product_id;
SELECT
o.order_id,
p.name AS product_name,
oi.quantity,
oi.unit_price,
oi.line_amount
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
ORDER BY o.order_id;
SELECT
o.order_id,
p.name AS product_name,
oi.quantity,
oi.unit_price,
oi.line_amount
FROM orders o, order_items oi, products p
WHERE o.order_id = oi.order_id
AND oi.product_id = p.product_id
ORDER BY o.order_id;
SELECT
o.order_id,
p.name AS product_name,
oi.quantity,
oi.line_amount
FROM orders o
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
group by o.order_id, product_name
ORDER BY o.order_id;
SELECT
o.order_id,
o.ordered_at,
o.total_amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE c.name = 'Kim Mina'
ORDER BY o.ordered_at DESC;
Lee Jisu인 고객의 주문 내역을 조회하라.SELECT
c.name
o.order_id,
o.ordered_at,
o.total_amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE c.name = 'Lee Jisu'
ORDER BY o.ordered_at DESC;
SELECT
o.order_id,
c.name,
o.status,
o.total_amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
WHERE o.status <> 'CANCELLED';
“결제가 아직 안 된 주문도 보고 싶다”
SELECT
o.order_id,
o.status AS order_status,
p.method,
p.status AS payment_status
FROM orders o
LEFT JOIN payments p
ON o.order_id = p.order_id
ORDER BY o.order_id;
SELECT
o.order_id,
o.status,
o.total_amount
FROM orders o
LEFT JOIN payments p ON o.order_id = p.order_id
WHERE p.order_id IS NULL;
select c.*, order_id from customers c
left join orders o on c.customer_id = o.customer_id
where order_id is null;
SELECT
c.customer_id,
c.name,
COUNT(o.order_id) AS order_count
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name
ORDER BY order_count DESC;
SELECT
p.product_id,
p.name,
SUM(oi.quantity) AS total_qty
FROM products p
JOIN order_items oi ON p.product_id = oi.product_id
GROUP BY p.product_id, p.name
ORDER BY total_qty DESC;
SELECT
o.order_id,
c.name AS customer_name,
o.ordered_at,
p.name AS product_name,
oi.quantity,
oi.line_amount
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
WHERE o.ordered_at >= NOW() - INTERVAL 7 DAY
ORDER BY o.ordered_at DESC;
SELECT
p.method,
SUM(p.paid_amount) AS total_sales
FROM payments p
GROUP BY p.method
ORDER BY total_sales DESC;
Q1. 주문 1건(order_id=1)의 주문자 이름과 주문일시를 조회하시오.
(orders + customers)
SELECT o.order_id, c.name AS customer_name, o.ordered_at
FROM orders o
JOIN customers c ON c.customer_id = o.customer_id
WHERE o.order_id = 1;
Q2. 결제가 존재하는 주문에 대해 주문번호, 고객명, 결제수단, 결제금액을 조회하시오.
(orders + customers + payments)
SELECT o.order_id, c.name AS customer_name, p.method, p.paid_amount
FROM orders o
JOIN customers c ON c.customer_id = o.customer_id
JOIN payments p ON p.order_id = o.order_id;
Q3.(서브쿼리 문제) 각 주문의 주문금액(orders.total_amount)과 “실제 주문상세 합계(SUM(order_items.line_amount))”를 함께 보여 차이가 있는 주문만 조회하시오.
(orders + order_items)
select o.order_id, o.total_amount, x.sum_line_amount
from orders o
join (
select order_id, sum(line_amount) as sum_line_amount
from order_items
group by order_id ) x on x.order_id = o.order_id
where o.tatal_amount != x.sum_line_amount;
select o.order_id, o.total_amount, (
select sum(oi.line_amount)
from order_items oi
where o.order_id = oi.order_id
) as total_line_amount
from orders o
where o.total_amount=total_line_amount;
원했던 모양은 위와 같지만 WHERE절에서는 별칭을 사용할 수 없다.
따라서, 아래와 같이 작성되어야 하기때문에 JOIN절 서브쿼리를 쓰는것이 더 나아보인다.
select o.order_id, o.total_amount, (
select sum(oi.line_amount)
from order_items oi
where o.order_id = oi.order_id
) as total_line_amount
from orders o
where o.total_amount=(
select sum(oi.line_amount)
from order_items oi
where o.order_id = oi.order_id
);
select *
from (
select
o.order_id,
o.total_amount,
(
select sum(oi.line_amount)
from order_items oi
where oi.order_id = o.order_id
) as total_line_amount
from orders o
) t
where t.total_amount != t.total_line_amount;
Q4. 주문상세 기준으로, 주문번호별 아이템 개수(라인 수)를 조회하시오.
(출력: order_id, item_lines)
SELECT oi.order_id, COUNT(*) AS item_lines
FROM order_items oi
GROUP BY oi.order_id;
Q5. 주문상세 기준으로 상품별 총 판매수량(quantity 합)을 조회하고, 판매수량 TOP 5를 출력하시오.
(order_items + products)
SELECT p.product_id, p.name, SUM(oi.quantity) AS total_qty
FROM order_items oi
JOIN products p ON p.product_id = oi.product_id
GROUP BY p.product_id, p.name
ORDER BY total_qty DESC
LIMIT 5;
Q6. 고객별 총 주문금액(orders.total_amount 합)을 조회하고, 총액 TOP 5를 출력하시오.
(orders + customers)
SELECT c.customer_id, c.name, SUM(o.total_amount) AS total_spend
FROM orders o
JOIN customers c ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.name
ORDER BY total_spend DESC
LIMIT 5;
Q7. 아직 결제가 없는 주문(미결제)을 조회하시오.
(orders LEFT JOIN payments)
SELECT o.order_id, o.customer_id, o.status, o.ordered_at
FROM orders o
LEFT JOIN payments p ON p.order_id = o.order_id
WHERE p.order_id IS NULL;
Q8. 주문상세와 상품을 조인해서, 주문 10번의 상품명/수량/단가/라인금액을 출력하시오.
(order_items + products)
SELECT oi.order_id, p.name AS product_name, oi.quantity, oi.unit_price, oi.line_amount
FROM order_items oi
JOIN products p ON p.product_id = oi.product_id
WHERE oi.order_id = 10
ORDER BY oi.order_item_id;
Q9. 고객별 주문 건수와 최근 주문일(ordered_at MAX)을 함께 조회하시오.
(orders + customers)
SELECT c.customer_id, c.name,
COUNT(o.order_id) AS order_cnt,
MAX(o.ordered_at) AS last_ordered_at
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.customer_id
GROUP BY c.customer_id, c.name;
주문이 없는 고객까지 전부 출력 (LEFT JOIN)
Q10. SHIPPED 상태 주문에 대해 주문번호, 고객명, 주문일시, 주문금액을 조회하시오.
(orders + customers)
SELECT o.order_id, c.name AS customer_name, o.ordered_at, o.total_amount
FROM orders o
JOIN customers c ON c.customer_id = o.customer_id
WHERE o.status = 'SHIPPED'
ORDER BY o.ordered_at DESC;