프로그래머스:sql 고득점 Kit

주문량이 많은 아이스크림들 조회하기

rabbit-jun 2026. 3. 1. 17:31

문제 링크:https://school.programmers.co.kr/learn/courses/30/lessons/133027

 

프로그래머스

SW개발자를 위한 평가, 교육의 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프

programmers.co.kr

유튜브 해설:https://youtu.be/h_SMMONN2bI

 


Q&A

 

질문
SQL에서 WINDOW FUNCTION은 SELECT절 말고 어디에 사용 가능해?

 

답변
1. 직접 사용 가능한 곳: ORDER BY 절
SELECT 절에서 구한 윈도우 함수 결과값을 화면에 출력(SELECT)하지 않더라도, 결과 정렬을 위해 ORDER BY 절에서 바로 계산하여 사용할 수 있습니다.

 

SELECT 직원이름, 부서, 급여
FROM 직원
ORDER BY RANK() OVER (PARTITION BY 부서 ORDER BY 급여 DESC);

 

 

2. 왜 WHERE나 GROUP BY에서는 못 쓸까요? (SQL 실행 순서)
그 이유는 데이터베이스가 SQL을 해석하고 실행하는 논리적 실행 순서 때문입니다.

실행 순서: FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY

윈도우 함수는 WHERE나 GROUP BY로 조건에 맞지 않는 데이터가 다 걸러지고, 그룹화까지 완료된 이후, 즉 SELECT 단계에서 살아남은 최종 결과 집합을 대상으로 계산됩니다. 그래서 그 앞 단계인 WHERE, GROUP BY, HAVING 절에서는 윈도우 함수를 인식할 수조차 없는 것이죠.

 

3. 실전 팁: WHERE 절에서 윈도우 함수 결과를 조건으로 쓰려면?
"각 부서별 급여 1위 직원만 뽑아라" 혹은 "최근 접속한 이력 3개만 가져와라" 같은 데이터 추출 작업을 할 때가 많습니다. 이때는 WHERE 절에 윈도우 함수를 직접 쓸 수 없으므로, 서브쿼리(Subquery)나 CTE(WITH 절)를 활용해 먼저 윈도우 함수로 순위나 값을 만들어 두고, 바깥 쿼리에서 필터링해야 합니다.

 


 

질문

WITH X AS (
    SELECT (F.TOTAL_ORDER + J.TOTAL_ORDER) AS FUSION_TOTAL_ORDER , F.SHIPMENT_ID FROM FIRST_HALF AS F
    JOIN JULY AS J ON F.SHIPMENT_ID = J.SHIPMENT_ID
          )

WITH Y AS(
     SELECT DENSE_RANK() OVER(ORDER BY FUSION_TOTAL_ORDER DESC) AS F_T, X.SHIPMENT_ID 
     FROM FIRST_HALF INNER JOIN X USING(SHIPMENT_ID)
    )

SELECT FLAVOR
FROM FIRST_HALF INNER JOIN Y USING(SHIPMENT_ID) 
WHERE F_T > 4

뭐가 문제야?

 

답변
1. WITH 구문의 중복 사용
가장 결정적인 원인입니다. WITH 절(CTE)을 여러 개 정의할 때는 WITH라는 키워드는 맨 처음에 딱 한 번만 쓰고, 나머지는 쉼표(,)로 이어가야 합니다. 두 번째 WITH 키워드를 쓰면 문법 에러가 발생합니다.

 

오류: WITH X AS (...), WITH Y AS (...)

정답: WITH X AS (...), Y AS (...)

 

2. USING 절과 테이블 별칭(Alias)의 충돌
Y를 정의하는 두 번째 쿼리에서 INNER JOIN X USING(SHIPMENT_ID)를 사용하셨습니다.
USING(컬럼명)을 사용하여 조인할 경우, 조인의 기준이 되는 컬럼은 두 테이블이 합쳐진 공통 컬럼으로 취급됩니다. 따라서 SELECT 절에서 X.SHIPMENT_ID처럼 특정 테이블의 별칭(Alias)을 붙이면 에러가 발생합니다. 그냥 SHIPMENT_ID라고만 적어주셔야 해요.

 


 

질문

SELECT FLAVOR,SUM(TOTAL_ORDER) FROM JULY GROUP BY FLAVOR, TOTAL_ORDER

이렇게 하면


|FLAVOR|TOTAL_OREDER|
|----------|----|
|strawberry | 520|
|strawberry | 220|

 

이렇게 나오는게 아니라

FLAVOR TOTAL_OREDER
strawberry 740


이렇게 나와야 하는거 아니야?




SELECT에 있는건 GROUP BY에 적어야 하니깐 GROUP BY FLAVOR 이런식으로 FLAVOR만 묶는건 못하잖아

 

답변
말씀하신 "SELECT에 있는 건 GROUP BY에 적어야 한다"는 규칙은 반은 맞고 반은 틀립니다. 정확히는 일반 컬럼에만 해당되는 규칙이고, SUM(), COUNT(), AVG() 같은 집계 함수(Aggregate Function)는 예외예요.

 

그 이유를 역할로 나누어 설명해 드릴게요.

GROUP BY에 적는 것: 데이터를 묶는 기준 (예: FLAVOR)

SELECT의 집계 함수: 그 묶인 그룹 안에서 계산된 결과 (예: SUM(TOTAL_ORDER))

 

 


정답

WITH X AS (
    SELECT (F.TOTAL_ORDER + J.TOTAL_ORDER) AS FUSION_TOTAL_ORDER ,F.FLAVOR FROM FIRST_HALF AS F
    JOIN (SELECT FLAVOR,SUM(TOTAL_ORDER) AS TOTAL_ORDER FROM JULY GROUP BY FLAVOR) AS J ON F.FLAVOR = J.FLAVOR
          ),
     Y AS(
     SELECT DENSE_RANK() OVER(ORDER BY FUSION_TOTAL_ORDER DESC) AS F_T,FLAVOR
     FROM FIRST_HALF INNER JOIN X USING(FLAVOR)
    )




SELECT FLAVOR
FROM FIRST_HALF INNER JOIN Y USING(FLAVOR) 
WHERE F_T < 4

 

 

 

 


보다 나은 정답

WITH X AS (
    SELECT F.FLAVOR, DENSE_RANK() OVER(ORDER BY F.TOTAL_ORDER +J.TOTAL_ORDER DESC) AS F_T
    FROM FIRST_HALF AS F JOIN (SELECT FLAVOR, SUM(TOTAL_ORDER) AS TOTAL_ORDER FROM JULY GROUP BY FLAVOR ) AS J 
    ON F.FLAVOR = J.FLAVOR
    )




SELECT FLAVOR
FROM FIRST_HALF INNER JOIN X USING(FLAVOR) 
WHERE F_T < 4

 


다른 사람의 풀이

WITH LIST AS( 
    SELECT * 
    FROM FIRST_HALF
    UNION ALL
    SELECT *
    FROM JULY
)


SELECT FLAVOR 
FROM LIST
GROUP BY FLAVOR
ORDER BY SUM(TOTAL_ORDER) DESC
LIMIT 3

 

 


 

반응형