본문 바로가기
SQL

실전 문제 풀이 (5)

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

오늘은 SQL 고급 문제를 풀어보려고 합니다. GPT한테 고급문제를 요청하니까 문제마다 테이블을 주는 것이 아니라 여러 테이블을 주고 그걸 JOIN 해가면서 푸는 문제를 주더라고요. 그래서 이번엔 문제별로 테이블을 작성하는 것이 아니기 때문에 보기는 조금 불편할 수 있을 것 같습니다.

 

- 테이블 생성

-- 주문 테이블
CREATE TABLE orders (
    order_id INT PRIMARY KEY,
    user_id INT,
    order_date DATE,
    amount INT
);

INSERT INTO orders (order_id, user_id, order_date, amount) VALUES
(1, 101, '2025-07-01', 500),
(2, 101, '2025-07-03', 300),
(3, 102, '2025-07-01', 200),
(4, 102, '2025-07-02', 150),
(5, 102, '2025-07-04', 400),
(6, 103, '2025-07-01', 700),
(7, 103, '2025-07-10', 100),
(8, 104, '2025-07-02', 250),
(9, 104, '2025-07-03', 350),
(10, 104, '2025-07-05', 500);

-- 사용자 테이블
CREATE TABLE users (
    user_id INT PRIMARY KEY,
    name VARCHAR(50),
    join_date DATE
);

INSERT INTO users (user_id, name, join_date) VALUES
(101, 'Alice', '2025-01-10'),
(102, 'Bob', '2025-02-14'),
(103, 'Charlie', '2025-03-20'),
(104, 'Diana', '2025-04-05');

-- 리뷰 테이블
CREATE TABLE reviews (
    review_id INT PRIMARY KEY,
    user_id INT,
    order_id INT,
    rating INT
);

INSERT INTO reviews (review_id, user_id, order_id, rating) VALUES
(1, 101, 1, 5),
(2, 101, 2, 4),
(3, 102, 3, 3),
(4, 102, 5, 5),
(5, 103, 6, 4),
(6, 104, 8, 2),
(7, 104, 10, 5);

 

생성한 테이블은 아래와 같다.

 

📦 orders (주문 테이블)

order_id user_id order_date amount
1 101 2025-07-01 500
2 101 2025-07-03 300
3 102 2025-07-01 200
4 102 2025-07-02 150
5 102 2025-07-04 400
6 103 2025-07-01 700
7 103 2025-07-10 100
8 104 2025-07-02 250
9 104 2025-07-03 350
10 104 2025-07-05 500

 

👤 users (사용자 테이블)

user_id name join_date
101 Alice 2025-01-10
102 Bob 2025-02-14
103 Charlie 2025-03-20
104 Diana 2025-04-05

 

⭐ reviews (리뷰 테이블)

review_id user_id order_id rating
1 101 1 5
2 101 2 4
3 102 3 3
4 102 5 5
5 103 6 4
6 104 8 2
7 104 10 5

 

문제 1 — 최근 주문 금액 TOP 2

각 사용자별로 가장 최근 주문일 기준으로 주문 금액 상위 2건을 구하시오.
단, 같은 날 여러 주문이 있을 경우 모두 포함하세요.

WITH rank_table AS (
  SELECT
    order_id,
    user_id,
    order_date,
    amount,
    DENSE_RANK() OVER (
      PARTITION BY user_id
      ORDER BY order_date DESC, amount DESC
      ) AS rn
  FROM orders
  )

SELECT
  order_id,
  user_id,
  order_date,
  amount
FROM rank_table
WHERE rn <= 2

 

 

 

문제 2 — 평균 이상 주문

사용자별 평균 주문 금액보다 높은 주문만 조회하시오.
결과에는 user_id, order_id, amount, avg_amount 컬럼이 포함되어야 함.

WITH avg_table AS (
  SELECT
    order_id,
    user_id,
    order_date,
    amount,
    AVG(amount) OVER (
      PARTITION BY user_id
      ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
      ) AS avg_amount
  FROM orders
  )

SELECT
  order_id,
  user_id,
  amount,
  avg_amount
FROM avg_table
WHERE amount > avg_amount

 

 

 

문제 3 — 연속 주문 고객

3일 연속으로 주문한 적이 있는 고객의 user_id와 해당 시작 날짜를 구하시오.

SELECT
  o1.user_id,
  o1.order_date
FROM orders o1
JOIN orders o2
  ON o1.user_id = o2.user_id
JOIN orders o3
  ON o1.user_id = o3.user_id
WHERE DATEDIFF(o2.order_date, o1.order_date) = 1 AND DATEDIFF(o3.order_date, o1.order_date) = 2

 

이 문제를 풀다보니 저번에 3일 연속 이상으로 주문한 고객 찾는 문제가 떠올라서 복습겸 한번 더 풀어보기로 했다.

WITH date_table AS (
  SELECT
    *,
    DATE_SUB(order_date, INTERVAL ROW_NUMBER() OVER (
      PARTITION BY user_id
      ORDER BY order_date
      ) DAY) AS day
  FROM orders
  )
  
SELECT
  user_id,
  day
FROM date_table
GROUP BY user_id, day
HAVING COUNT(*) >= 3

 

 

 

문제 4 — 리뷰 점수 순위

모든 리뷰의 평균 점수를 구하고, 이 평균보다 높은 평균 점수를 가진 사용자들을 평균 점수 내림차순으로 출력하시오.
출력 컬럼: user_id, avg_rating

WITH avg_table AS (
  SELECT
    *,
    AVG(rating) OVER (
      PARTITION BY user_id
      ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
      ) AS avg_rating,
    AVG(rating) OVER (
      ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
      ) AS total_avg_rating
  FROM reviews
  )
  
SELECT
 DISTINCT user_id,
 avg_rating,
 total_avg_rating
FROM avg_table
WHERE avg_rating > total_avg_rating

 

 

 

문제 5 — 첫 주문과 마지막 주문 간 차이

각 사용자별로 첫 주문일과 마지막 주문일의 날짜 차이를 계산하시오.
컬럼명: user_id, first_order, last_order, day_diff

WITH date_table AS (
  SELECT
  *,
  FIRST_VALUE(order_date) OVER (
    PARTITION BY user_id
    ) AS first_order,
  LAST_VALUE(order_date) OVER (
    PARTITION BY user_id
    ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
    ) AS last_order
  FROM orders
  )

SELECT
  user_id,
  first_order,
  last_order,
  DATEDIFF(last_order, first_order) AS day_diff
FROM date_table

 

 

 


 

오늘 GPT 5로 버전이 바뀌었는데. 뭔가 문제설명이 조금 난해해졌다. 내가 문제 생성 요청을 잘못한건가? 다음부터 신경 써야겠다.

'SQL' 카테고리의 다른 글

실전 문제 풀이 (4)  (3) 2025.08.15
실전 문제 풀이 (3)  (2) 2025.08.13
실전 문제 풀이 (2)  (3) 2025.08.11
실전 문제 풀이 (1)  (3) 2025.08.09
조건 처리 함수 - MySQL  (0) 2025.08.07