본문 바로가기
Data Science/SQL

[SQL/오답] 골든아워 고객 찾기: 다중 조건 집계와 시간대 필터링 TIME함수 (Leetcode3705 Medium)

by 에르모사 쩐뉴 2026. 2. 19.

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다. 혼잡한 시간대에 방문하면서도 매너(평점)까지 좋은 고객들이기 때문이다. 이들을 타겟으로 피크 타임 전용 쿠폰을 발행하는 등의 마케팅 쿼리로 활용될 수 있다."