3705. Find Golden Hour Customers
1. Problem
피크 타임에 자주 주문하고 높은 만족도를 보이는 '골든 아워 고객'을 추출해야 한다.
- 조건 1: 최소 주문 횟수 3회 이상이다.
- 조건 2: 전체 주문 중 60% 이상이 피크 타임(11-14시 또는 18-21시)에 발생해야 한다.
- 조건 3: 평균 평점이 4.0 이상이어야 한다.
- 조건 4: 전체 주문의 50% 이상에 대해 리뷰(평점)를 남겼어야 한다.
- 결과: 평균 평점 내림차순, 고객 ID 내림차순으로 정렬한다.
2. Solution: 집계 함수와 HAVING 절을 활용한 원스톱 필터링
TIME() 함수로 시각만 추출한 뒤, AVG(CASE...) 패턴을 사용하여 비율을 계산하고 HAVING 절에서 모든 조건을 검증한다.
3. Takeaway: 오답 분석을 통한 교훈
- 비교 연산자의 누락:
- 오답 상황: AND AVG(order_rating) (조건값 없이 함수만 기재)
- 분석: SQL에서 AND 뒤에는 반드시 컬럼/함수 >= 값 형태의 완성된 조건식이 와야 한다. 정답 쿼리처럼 AVG(order_rating) >= 4라고 명시해야 논리적 판단이 가능하다.
- 괄호와 구문 오류:
- 오답 상황: OR ( (TIME(...) (열린 괄호가 닫히지 않거나 불필요한 중첩 발생)
- 분석: 특히 OR 연산자와 BETWEEN을 섞어 쓸 때는 괄호의 짝이 맞는지 엄격히 확인해야 한다.
- AVG(CASE...)의 강력함:
- 특정 조건의 비율을 구할 때 SUM(CASE...)/COUNT(*)를 써도 되지만, AVG(CASE WHEN [조건] THEN 1 ELSE 0 END)를 쓰면 더 간결하게 비율(0~1)을 얻을 수 있다.
정답 쿼리
### 정답 쿼리 ###
SELECT customer_id,
COUNT(*) AS total_orders,
ROUND(
AVG(CASE WHEN (TIME(order_timestamp) BETWEEN '11:00:00' AND '14:00:00') #반올림 처리
OR (TIME(order_timestamp) BETWEEN '18:00:00' AND '21:00:00') THEN 1 ELSE 0 END) * 100,0) AS peak_hour_percentage,
ROUND(AVG(order_rating),2) AS average_rating #반올림 처리
FROM restaurant_orders
GROUP BY customer_id
HAVING COUNT(*) >= 3 # 조건1 최소주문조건
AND AVG(order_rating) >= 4 # 조건2 평점4이상
AND COUNT(order_rating)/COUNT(*) >= 0.5 # 조건3 평가율 50%이상
AND AVG(CASE WHEN (TIME(order_timestamp) BETWEEN '11:00:00' AND '14:00:00') # 조건4 피크시간 60%이상
OR (TIME(order_timestamp) BETWEEN '18:00:00' AND '21:00:00') THEN 1 ELSE 0 END) >= 0.6
ORDER BY average_rating DESC, customer_id DESC; # 정렬 조건
코드 상태
✔ 최소 주문 조건
✔ peak ≥ 60%
✔ 평점 작성 ≥ 50%
✔ 평균 평점 ≥ 4.0
✔ 반올림 처리
✔ 정렬 조건
👉 이제 통과해야
오답쿼리
### 오답 쿼리 ###
SELECT customer_id,
COUNT(*) AS total_orders,
ROUND(AVG(CASE WHEN (TIME(order_timestamp) BETWEEN '11:00:00' AND '14:00:00') OR ( (TIME(order_timestamp) BETWEEN '18:00:00' AND '21:00:00') THEN 1 ELSE 0 END)*100,0) AS peak_hour_percentage,
ROUND(AVG(order_rating),2) AS average_rating
FROM restaurant_orders
GROUP BY customer_id
HAVING COUNT(*) >= 3
AND AVG(order_rating)
AND COUNT(order_rating)/COUNT(*) >= 0.5
AND AVG(CASE WHEN (TIME(order_timestamp) BETWEEN '11:00:00' AND '14:00:00') OR ( (TIME(order_timestamp) BETWEEN '18:00:00' AND '21:00:00') THEN 1 ELSE 0 END) >= 0.6
ORDER BY average_rating DESC, customer_id DESC;
틀린 부분 톺아보기
AVG(CASE WHEN (TIME(...) BETWEEN ...)
OR ( (TIME(...) BETWEEN ...)
THEN 1 ELSE 0 END)*100
👉 OR ( 뒤 괄호가 하나 더 열리고 안 닫힘
👉 END)*100 위치도 잘못됨
AND AVG(order_rating)
이건 조건이 아님❌→ 반드시 비교 연산 필요
문제 조건: average rating >= 4.0
- 시각적 가이드: 시계 모양을 그려 점심시간(11-14)과 저녁 시간(18-21)을 색칠해 보라. 이 영역에 주문 데이터의 60%가 집중된 고객을 찾는 과정임을 강조하면 이해가 빠르다.
- 실무적 제언: "식당 입장에서는 이들이 가장 중요한 VIP다. 혼잡한 시간대에 방문하면서도 매너(평점)까지 좋은 고객들이기 때문이다. 이들을 타겟으로 피크 타임 전용 쿠폰을 발행하는 등의 마케팅 쿼리로 활용될 수 있다."
'Data Science > SQL' 카테고리의 다른 글
| [SQL/오답] 유저별 지배적 반응과 비율 계산 (Leetcode3808 Medium) (0) | 2026.02.20 |
|---|---|
| [SQL/실전] 이탈 위기 고객 탐지: CTE와 윈도우 함수 활용 상태 분석 (Leetcode3716 Medium) (0) | 2026.02.20 |
| [SQL/오답] 평점 양극화 분석: 집계 함수와 HAVING 절의 제약 사항 (Leetcode3642 Medium) (0) | 2026.02.19 |
| [SQL/풀이] 상/하반기 연비 비교: 단순 집계를 넘어선 성과 분석 (LeetCode3601 Medium) (1) | 2026.02.18 |
| [SQL/오답] 시계열 데이터의 선후 관계: COVID-19 회복 기간 분석 (Leetcode3586 Medium) (0) | 2026.02.18 |