본문 바로가기
SQL

실전 문제 풀이 (7)

by 바른곰의 SQL천국 2025. 8. 21.

문제 1 — 고객별 최신 주문과 직전 주문 비교

DROP TABLE IF EXISTS orders;
CREATE TABLE orders (
  order_id INT AUTO_INCREMENT PRIMARY KEY,
  customer_id INT NOT NULL,
  order_date DATETIME NOT NULL,
  amount DECIMAL(10,2) NOT NULL
);

INSERT INTO orders (customer_id, order_date, amount) VALUES
(1,'2025-07-01 10:00:00', 100.00),
(1,'2025-07-10 09:30:00', 150.00),
(1,'2025-07-20 12:00:00', 200.00),
(2,'2025-07-05 14:00:00', 50.00),
(2,'2025-06-01 12:00:00', 80.00),
(3,'2025-07-20 11:00:00', 120.00),
(3,'2025-07-20 11:00:00', 120.00),
(3,'2025-06-10 08:00:00', 100.00),
(4,'2025-07-22 09:00:00', 500.00);

 

요구사항
고객별로 가장 최근 주문과 그 직전 주문을 한 행에 표시하고, 두 주문 간 날짜 차이와 금액 변화를 계산하세요.

  • 결과 컬럼: customer_id, recent_order_id, recent_order_date, recent_amount, prev_order_id, prev_order_date, prev_amount, days_between, amount_change
  • 오직 이전 주문이 존재하는 고객만 출력
  • amount_change 절댓값이 큰 순서로 정렬, 동률 시 customer_id 오름차순
WITH rank_table AS (
  SELECT
    customer_id,
    order_date,
    amount,
    ROW_NUMBER() OVER (
      PARTITION BY customer_id
      ORDER BY order_date DESC
      ) AS rn
  FROM orders
  )
  

SELECT
  r1.customer_id,
  r1.order_date AS recent_order_date,
  r1.amount AS recent_amount,
  r2.order_date AS prev_order_date,
  r2.amount AS prev_amount,
  DATEDIFF(r1.order_date, r2.order_date) AS days_between,
  r1.amount - r2.amount AS amount_change
FROM rank_table r1
JOIN rank_table r2
  ON r1.customer_id = r2.customer_id
  AND r1.rn = r2.rn - 1
WHERE r1.rn = 1
ORDER BY ABS(amount_change) DESC, customer_id

 

 

 

문제 2 — 주문 취소율이 높은 고객 찾기

DROP TABLE IF EXISTS customer_orders;
CREATE TABLE customer_orders (
  order_id INT PRIMARY KEY,
  customer_id INT,
  order_date DATE,
  status VARCHAR(20) -- 'completed', 'cancelled'
);

INSERT INTO customer_orders (order_id, customer_id, order_date, status) VALUES
(1, 1, '2025-07-01', 'completed'),
(2, 1, '2025-07-02', 'cancelled'),
(3, 1, '2025-07-03', 'completed'),
(4, 1, '2025-07-04', 'cancelled'),
(5, 2, '2025-07-01', 'completed'),
(6, 2, '2025-07-02', 'cancelled'),
(7, 2, '2025-07-03', 'cancelled'),
(8, 2, '2025-07-04', 'completed'),
(9, 2, '2025-07-05', 'cancelled'),
(10, 3, '2025-07-01', 'completed'),
(11, 3, '2025-07-02', 'completed'),
(12, 3, '2025-07-03', 'completed'),
(13, 4, '2025-07-01', 'cancelled'),
(14, 4, '2025-07-02', 'cancelled'),
(15, 4, '2025-07-03', 'cancelled');

 

요구사항
고객별 전체 주문 건수, 취소 건수, 취소율(%)을 구하고 취소율이 높은 순으로 정렬하세요.

  • 결과 컬럼: customer_id, total_orders, cancelled_orders, cancel_rate
  • 주문이 3건 이상인 고객만 포함
  • 취소율은 소수점 둘째 자리까지 표시
  • 취소율이 같은 경우 total_orders가 많은 순서로 정렬
WITH total_order_table AS (
  SELECT
    customer_id,
    COUNT(*) AS total_orders,
    SUM(CASE WHEN status = 'cancelled' THEN 1 ELSE 0 END) AS cancelled_orders
  FROM customer_orders
  GROUP BY customer_id
  ),
  
cancle_pct_table AS (
  SELECT
    *,
    cancelled_orders / total_orders * 100 AS cancle_rate
  FROM total_order_table
  )


SELECT 
  customer_id,
  total_orders,
  cancelled_orders,
  ROUND(cancle_rate, 2) AS cancle_rate
FROM cancle_pct_table
WHERE total_orders >= 3
ORDER BY cancle_rate DESC, total_orders DESC

 

 

 

문제 3 — 월별 상품 매출 상위 3개와 누적 비중

DROP TABLE IF EXISTS sales;
CREATE TABLE sales (
  sale_id INT AUTO_INCREMENT PRIMARY KEY,
  product_id INT,
  store_id INT,
  sale_date DATE,
  units INT,
  unit_price DECIMAL(10,2)
);

INSERT INTO sales (product_id, store_id, sale_date, units, unit_price) VALUES
(101,1,'2025-05-10', 10, 20.00),
(101,2,'2025-05-12',  5, 20.00),
(102,1,'2025-05-11', 20, 10.00),
(103,1,'2025-05-15',  2,100.00),
(104,1,'2025-05-20', 50, 2.00),
(101,1,'2025-06-05', 30, 20.00),
(102,1,'2025-06-10', 10, 10.00),
(103,1,'2025-06-12',  5,100.00),
(104,1,'2025-06-25',100, 2.00),
(101,1,'2025-07-02', 25, 20.00),
(102,1,'2025-07-03', 40, 10.00),
(103,1,'2025-07-05', 10,100.00),
(104,1,'2025-07-08', 80, 2.00),
(105,1,'2025-07-09',  1,500.00);

 

요구사항
월 단위로 상품별 총 판매량과 총 매출을 계산하고, 각 월 매출 상위 3개 상품과 그 누적 매출 비중을 구하세요.

  • 결과 컬럼: month, product_id, total_units, total_revenue, revenue_rank, cumulative_revenue_pct
  • 월별 매출 3위까지 출력
  • month 오름차순, revenue_rank 오름차순 정렬
WITH product_month_sales AS (
  SELECT
    DATE_FORMAT(sale_date, '%Y-%m') AS month,
    product_id,
    SUM(units * unit_price) AS total_revenue
  FROM sales
  GROUP BY DATE_FORMAT(sale_date, '%Y-%m'), product_id
),

rank_table AS (
  SELECT
    *,
    ROW_NUMBER() OVER (
      PARTITION BY month
      ORDER BY total_revenue DESC
      ) AS revenue_rank,
    SUM(total_revenue) OVER (
      PARTITION BY month
      ) AS month_total_revenue
  FROM product_month_sales
),

pct_table AS (
  SELECT
    *,
    SUM(total_revenue) OVER (
      PARTITION BY month
      ORDER BY total_revenue DESC
      ) / month_total_revenue * 100 AS cumulative_revenue_pct
  FROM rank_table
)

SELECT
  month,
  product_id,
  total_revenue,
  revenue_rank,
  cumulative_revenue_pct
FROM pct_table
WHERE revenue_rank <= 3
ORDER BY month, revenue_rank

 

 


 

GPT 5로 바뀌고 문제 난이도도 급격히 상승했다. 결국 한 문제도 못풀어서 GPT한테 답물어보고 뜯어보는 식으로 공부했다. 시간이 꽤 오래걸린다. 그래서 앞으로는 이런 난이도의 문제로 3개정도씩만 풀어보려고 한다...

'SQL' 카테고리의 다른 글

실전 문제 풀이 (9)  (1) 2025.08.25
실전 문제 풀이 (8)  (0) 2025.08.23
실전 문제 풀이 (6)  (0) 2025.08.19
실전 문제 풀이 (5)  (5) 2025.08.17
실전 문제 풀이 (4)  (3) 2025.08.15