[SQL 프로그래머스 문제풀이] (JOIN) '5월 식품들의 총매출 조회하기'

윤상혁·2025년 11월 3일

프로그래머스 LEVEL-4 문제입니다.

직전 게시글 문제랑 같은 레벨이지만 다른 난이도인 거 같아요. 아무래도 직전 게시글이 LEVEL-4가 아니라 5인 거 같음...(다른 사람 해답 풀이과정 게시글 참고했는데, 거기서 'LEVEL-5'라고 적혀있는 거 보면..)

이번엔 제가 처음으로 AI(CLAUDE)의 도움을 안 받고 스스로 문제를 풀었습니다..!! (와우..ㅎㅎ..)


1. 문제 소개

*테이블
1. FOOD_PRODUCT(PRODUCT_ID, PRODUCT_NAME, PRODUCT_CD, CATEGORY, PRICE)

  1. FOOD_ORDER(ORDER_ID, PRODUCT_ID(FK.비식별관계(일반 참조)), AMOUNT, PRODUCE_DATE, IN_DATE, OUT_DATE, FACTORY_ID, WAREHOUSE_ID)

*문제 정리

1.생산일자(PRODUCE_DATE, FOOD_ORDER 테이블)가 2022-05인 식품들

2.식품 ID(PRODUCT_ID, FOOD_PRODUCT 테이블), 식품 이름(PRODUCT_NAME, FOOD_PRODUCT 테이블), 총매출(유도 속성? 새로운 열을 만들어서 계산: PRICE * AMOUNT 같은데? 계산 테스트해보니 맞음.) 조회.

3.총매출 기준으로 내림차순 정렬, 총매출이 같으면 식품 ID 기준으로 오름차순 정렬.

->문제 정리에서 2번을 보면, 저는 문제를 읽으면서 이렇게 생각했습니다.

1.예시를 보니 AMOUNT를 합쳐야하는데, GROUP BY 사용해야 함.(ORDER_ID 기준으로 PK이므로, 중복이 허용될 수 밖에 없음.)

  1. 그리고 식품 이름이라고 한 거 보니, 2개의 테이블이 있는데 그 중에서 PK로 쓰는 첫번째 테이블을 지칭하는 거 보니 이 부분 유심히 봐봐.

2. 문제 풀이

2-1. '문제 정리' 1번 풀이

<정답 코드>

SELECT
    PRODUCT_ID
FROM FOOD_ORDER
WHERE PRODUCE_DATE BETWEEN '2022-05-01' AND '2022-05-31'

저는 날짜를 조회해야하므로, 'BETWEEN' 개념을 사용하였습니다.

TMI이지만, 이 BETWEEN 사용 시에도 여러번 틀렸습니다.

맨 처음에는,

WHERE PRODUCE_DATE BETWEEN CONVERT(DATE, '2022-05-01') AND CONVERT(DATE, '2022-05-31') -- MSSQL 언어 문법

이렇게 MSSQL 문법을 사용했고,

그 다음은,

WHERE PRODUCE_DATE BETWEEN (DATE, '2022-05-01') AND (DATE, '2022-05-31') -- 허용 안됨.

이는 허용이 안 되었고,
최종적으로 저 정답 코드를 사용했습니다.

이를 언급하는 이유는,
'각 SQL 언어에 맞는 문법이 있음'을 강조하기 위함입니다.

그리고, 저는 이 작업이 끝난 후에,
직전 게시글에 푼 문제처럼 단순 ID만이 아닌 NAME까지 알고 싶었습니다.
->이 방법은, JOIN 후 해당 열을 선택하면 되는데, 일단 문제에서 요구하는 것만 풀 것이므로 보류하도록 하겠습니다.


2-2. '문제 정리' 2번 풀이

근데 '문제 정리'의 2번을 보아하니 JOIN을 해야되는 거처럼 보입니다.

그 이유는 다음과 같습니다.

*이유

1.유도 속성에서 AMOUNT와 PRICE로 값을 구해야한다.

2.위 2-1번에서 말한 것처럼 PRODUCT_ID 뿐만 아니라 PRODUCT_NAME까지 알고 싶다.

그럼 우리는 '무슨 조인?'을 하며 '어떤 공통된 열(속성)'을 기준으로 조인을 할 것인지 정해야 합니다.

*공통 속성: PRODUCT_ID -> PK이자 FK이니깐

*조인: INNER JOIN.

조인에서 저는 처음에는 'LEFT OUTER JOIN'을 선택했습니다.
그 이유는 다음과 같습니다.

*'LEFT OUTER JOIN'을 선택한 이유

테이블 크기는 '왼쪽 테이블(FOOD_PRODUCT) >= 오른쪽 테이블(FOOD_ORDER)'.

식품들 정보는 다 살려두면서 겹치지 않는 부분만 FOOD_ORDER 테이블의 속성들을 모두 NULL 처리하면 깔끔하다.

PRODUCT_ID는 공통된 속성(열)이자, 왼쪽 테이블에 온전히 있으므로, 이 부분은 원본 그대로 ALL 유지됨.

그렇게 해서 결과를 돌려봤습니다.

그런데 뭔가 이상한 느낌이 들었습니다.

뭔가 INNER JOIN(교집합)으로도 같은 결과가 나올 거 같다는 생각이 든 것입니다.

그래서 INNER JOIN으로 바꿔서 결과를 돌려봤습니다.

어 결과가 다릅니다.

곰곰이 생각해봤습니다.

당연히 다른 이유가 있었습니다.

※결과가 다른 이유

FP.PRODUCT_ID는 공통된 속성에 특히 왼쪽 테이블 열입니다.
그니깐 ON 조건은 같은 거지만, 어쨋든 LEFT OUTER JOIN은 결과가 다 나오는 게 당연한 겁니다.
반면, INNER JOIN은 말 그대로 공통된 부분들만 추려내므로, 정답은 INNER JOIN이 맞습니다.

(결과를 보면, 왼쪽 조인 시에 중간에 번호가 건너뛴 거는 원래 데이터 형태가 그런 거 같습니다. 일정하게 그런 규칙들이 보입니다.)

그 다음은
1. 각 테이블에 별칭을 지어주고(간편성 목적)
2. 2-1번의 WHERE절 조건을 붙이고
3. GROUP BY를 실행합니다.
->GROUP BY 열은 FO.PRODUCT_ID로 하고, SELECT에 유도 속성 열을 추가합니다.
->GROUP_BY 열을 FP.PRODUCT_ID가 아닌 FO.PRODUCT_ID로 선택한 이유는, 당연히 FP.PRODUCT_ID는 PK(기본키)이므로 중복 자체가 허용될 수 없으므로 FO.PRODUCT_ID를 사용합니다.
->엄밀히 말하면, 틀린 설명입니다. 밑에 설명을 참고하시면 됩니다. 제가 말하고 싶은 부분이 밑 부분 설명입니다.

<틀린 이유>

->좀 더 명확한 설명은, FO.PRODUCT_ID는 FK(외래키)로 중복이 있을 수 있으므로, 같은 상품의 여러 주문을 하나로 묶기 위해 GROUP BY 사용
->GROUP BY의 개념을 정확히 이해하고, 결과표를 보면서 이해하면 쉽게 이해가 될 것입니다.

SELECT
    FP.PRODUCT_ID,
    FP.PRODUCT_NAME,
    (FP.PRICE * FO.AMOUNT) AS TOTAL_SALES
FROM FOOD_PRODUCT FP INNER JOIN FOOD_ORDER FO
ON FP.PRODUCT_ID = FO.PRODUCT_ID
WHERE FO.PRODUCE_DATE BETWEEN '2022-05-01' AND '2022-05-31'
GROUP BY FO.PRODUCT_ID

하지만, 이렇게 하면 오답이 나옵니다.

GROUP BY를 하기 전에 SUM(집계)하는 것을 빼먹었기 때문입니다.

<GROUP BY 안하고 결과 낸 것>

<GROUP BY 하고 결과 낸 것>

이 사진들을 유심히 보면,
GROUP BY는 그룹화만 하는 성질만을 가지고 있으므로,
SUM(집계)가 따로 없으면, 여러 행(중복 행)을 한 행으로 합치지만, 다른 행은 무시하고 버려버립니다.

그래서 SUM을 추가합니다.

<'SUM TEST'>

이렇게 SUM이 잘 작동되는 것을 확인했으므로,

<정답 코드>

SELECT
    FP.PRODUCT_ID,
    FP.PRODUCT_NAME,
    -- SUM(FO.AMOUNT)
    FP.PRICE * SUM(FO.AMOUNT) AS TOTAL_SALES
FROM FOOD_PRODUCT FP INNER JOIN FOOD_ORDER FO
ON FP.PRODUCT_ID = FO.PRODUCT_ID
WHERE FO.PRODUCE_DATE BETWEEN '2022-05-01' AND '2022-05-31'
GROUP BY FO.PRODUCT_ID

2-3. '문제 정리' 3번 풀이

여기는 세부 조건만 작성하면 됩니다.
->ORDER BY절

<최종 정답 코드>

SELECT
    FP.PRODUCT_ID,
    FP.PRODUCT_NAME,
    -- SUM(FO.AMOUNT)
    FP.PRICE * SUM(FO.AMOUNT) AS TOTAL_SALES
FROM FOOD_PRODUCT FP INNER JOIN FOOD_ORDER FO
ON FP.PRODUCT_ID = FO.PRODUCT_ID
WHERE FO.PRODUCE_DATE BETWEEN '2022-05-01' AND '2022-05-31'
GROUP BY FO.PRODUCT_ID
ORDER BY TOTAL_SALES DESC, FP.PRODUCT_ID ASC;

3. 마무리

이렇게 해서 이번 LEVEL-4 문제를 풀어보았습니다.

직전 게시글 문제보다는 훨씬 간편하네요.

다음에 또 뵙도록 하겠습니다.~~ :) bb

profile
통합형 개발자. 기획부터 개발, 자동화까지. 문제를 구조적으로 이해하고, AI를 능동적으로 활용해 본질적인 해결책을 제시하는 사람입니다.

0개의 댓글