본문 바로가기

Skill Sets/SQL

[SQL] 년, 월, 성별 별 상품 구매 회원 수 구하기(프로그래머스/MySQL/Level 4)

SMALL

안녕하세요! 데코입니다!

 

오늘은 프로그래머스 코딩테스트 연습에 있는 "년, 월, 성별 별 상품 구매 회원 수 구하기" 문제를 포스팅하려고 합니다!

 

바로 포스팅 시작할게요! :)

(출처 : https://school.programmers.co.kr/learn/courses/30/lessons/131532)


 

1. 문제 :  년, 월, 성별 별 상품 구매 회원 수 구하기(Lv. 4)

 

 


 

2. 문제 설명

다음은 어느 의류 쇼핑몰에 가입한 회원 정보를 담은 USER_INFO 테이블과

 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블입니다.

 

USER_INFO 테이블은 아래와 같은 구조로 되어있으며 USER_ID, GENDER, AGE, JOINED는

각각 회원 ID, 성별, 나이, 가입일을 나타냅니다.

 

[ 테이블 구조('USER_INFO') ]

COLUMN NAME TYPE NULLABLE
USER_ID INTEGER FALSE
GENDER TINYINT(1) TRUE
AGE INTEGER TRUE
JOINED DATE FALSE

 

GENDER 컬럼은 비어있거나 0 또는 1의 값을 가지며

0인 경우 남자를, 1인 경우는 여자를 나타냅니다.

ONLINE_SALE 테이블은 아래와 같은 구조로 되어있며,

ONLINE_SALE_ID, USER_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE는

각각 온라인 상품 판매 ID, 회원 ID, 상품 ID, 판매량, 판매일을 나타냅니다.

 

[ 테이블 구조('ONLINE_SALE') ]

COLUMN NAME TYPE NULLABLE
ONLINE_SALE_ID INTEGER FALSE
USER_ID INTEGER FALSE
PRODUCT_ID INTEGER FALSE
SALES_AMOUNT INTEGER FALSE
SALES_DATE DATE FALSE

 

동일한 날짜, 회원 ID, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.

 

[ 문제 ]

USER_INFO 테이블과 ONLINE_SALE 테이블에서

년, 월, 성별 별로 상품을 구매한 회원수를 집계하는 SQL문을 작성해주세요.

결과는 년, 월, 성별을 기준으로 오름차순 정렬해주세요.

이때, 성별 정보가 없는 경우 결과에서 제외해주세요.

 

 

[ 예시 ]

 

예를 들어 USER_INFO 테이블이 다음과 같고

USER_ID GENDER AGE JOINED
1 1 26 2021-06-01
2 NULL NULL 2021-06-25
3 0 NULL 2021-06-30
4 0 31 2021-07-03
5 1 25 2021-07-09
6 1 33 2021-07-14

 

ONLINE_SALE 테이블이 다음과 같다면

ONLINE_SALE_ID USER_ID PRODUCT_ID SALES_AMOUNT SALES_DATE
1 1 54 1 2022-01-01
2 1 3 2 2022-01-25
3 4 34 1 2022-01-30
4 6 253 3 2022-02-03
5 2 31 2 2022-02-09
6 5 35 1 2022-02-14
7 5 57 1 2022-02-18

 

2022년 1월에 상품을 구매한 회원은

USER_ID 가 1(GENDER=1), 4(GENDER=0)인 회원들이고,


2022년 2월에 상품을 구매한 회원

USER_ID 가 2(GENDER=NULL), 5(GENDER=1), 6(GENDER=1)인 회원들 이므로,

년, 월, 성별 별로 상품을 구매한 회원수를 집계하고,

년, 월, 성별을 기준으로 오름차순 정렬하면 다음과 같은 결과가 나와야 합니다.

 

[ 출력 결과 ]

YEAR MONTH GENDER USERS
2022 1 0 1
2022 1 1 1
2022 2 1 2

 


 

3. 문제 풀이

-- 1안
SELECT  YEAR(A.SALES_DATE) AS YEAR
        , MONTH(A.SALES_DATE) AS MONTH
        , B.GENDER 
        , COUNT(DISTINCT A.USER_ID) AS USERS
  FROM  ONLINE_SALE A
  LEFT
  JOIN  USER_INFO B
    ON  A.USER_ID = B.USER_ID
 WHERE  B.GENDER = 0
        OR B.GENDER = 1
 GROUP
    BY  YEAR(A.SALES_DATE)
        , MONTH(A.SALES_DATE)
        , B.GENDER
 ORDER
    BY  YEAR ASC
        , MONTH ASC 
        , GENDER ASC

 

 

이번 문제는 총 1안 한 가지로 작성했습니다!

 

#  1안 풀이 설명

# [ 문제 접근 설명 ]


문제를 읽고 조건에 맞는 쿼리를 작성하기 위해서 다음과 같이  네 가지 단계로 진행했어요!

1. ONLINE_SALE 테이블을 기준으로 USER_INFO 테이블과 조인하기(JOIN)
2. GENDER 값이 존재하는 데이터만 조회하기(WHERE)
3. 년도, 월, 성별 별 회원 수 집계하기(GROUP BY)
4. 년도, 월, 성별 기준으로 정렬(ORDER BY)

 

# [ 1안 쿼리 작성 설명 ]

 

 1  첫 번째 단계에서는 ONLINE_SALE 테이블을 기준으로 USER_INFO 테이블과 조인을 했습니다!

 

공통으로 가지고 있는 컬럼인 USER_ID를 이용해서 ON 조건을 써주었고

 

ONLINE_SALE 테이블을 기준으로 LEFT JOIN 하였습니다.

 


SELECT  *

   FROM  ONLINE_SALE A
    LEFT
     JOIN  USER_INFO B
        ON  A.USER_ID = B.USER_ID

 

 2  두 번째 단계에서는 GENDER 값이 존재하는 데이터만 필터링해주었어요!

 

저번 포스팅에서 적은 것과 같이 최대한 NOT 사용을 지양해서

 

WHERE문에서 GENDER가 0 또는 1인 값을 OR을 이용해서 나타내었습니다.

 


SELECT  *

   FROM  ONLINE_SALE A
    LEFT
     JOIN  USER_INFO B
        ON  A.USER_ID = B.USER_ID
WHERE  B.GENDER = 0
               OR B.GENDER = 1

 

 3  세 번째 작업은 년도, 월, 성별 별로 GROUP BY를 이용해 집계해주었습니다!

 

또 회원 수를 구하기 위해서 COUNT 함수와 DISTINCT 함수를 이용해서 산출했어요!

 

DISTINCT를 사용한 이유는, 동일한 유저가 같은 날에 다른 주문을 했을 수도 있으니까

 

고유한 회원의 수를 세기 위해서는 DISTINCT를 사용했습니다!

 


SELECT  YEAR(A.SALES_DATE) AS YEAR

                , MONTH(A.SALES_DATE) AS MONTH
                , B.GENDER 
                , COUNT(DISTINCT A.USER_ID) AS USERS
   FROM  ONLINE_SALE A
    LEFT
     JOIN  USER_INFO B
        ON  A.USER_ID = B.USER_ID
WHERE  B.GENDER = 0
               OR B.GENDER = 1
 GROUP
          BY  YEAR(A.SALES_DATE)
                 , MONTH(A.SALES_DATE)
                 , B.GENDER

 

 4  마지막으로는 요구사항에 맞게 정렬했어요!

년(YEAR) 기준 오름차순 정별,

 

월(MONTH) 기준 오름차순 정렬.

 

그리고 성별(GENDER) 기준 오름차순으로 정렬했습니다!

 


SELECT  YEAR(A.SALES_DATE) AS YEAR
                , MONTH(A.SALES_DATE) AS MONTH
                , B.GENDER 
                , COUNT(DISTINCT A.USER_ID) AS USERS
   FROM  ONLINE_SALE A
    LEFT
     JOIN  USER_INFO B
        ON  A.USER_ID = B.USER_ID
WHERE  B.GENDER = 0
               OR B.GENDER = 1
 GROUP
          BY  YEAR(A.SALES_DATE)
                 , MONTH(A.SALES_DATE)
                 , B.GENDER
 ORDER
          BY  YEAR ASC
                 , MONTH ASC 
                 , GENDER ASC

 

 

정답...!


 

4. 데코의 문제 풀이 후기

이번 문제는 LEVEL 4인 문제임에도

 

두 테이블을 JOIN하고 GROUP BY하면 되는 어렵지 않은 문제네요!

 

다른 분들이 실수할 만한 것으로는 DISTINCT 함수를 빼먹는 거 정도 있을 것 같습니다!


이 외에는 이전 문제들에서 모두 다룬 것들을 이용해서

따로 코멘트할 것은 없네요!

혹시나 더 좋은 쿼리나 어렵게 느껴지신 부분이 있다면 댓글로 남겨주세요! 

 



이번 문제는 2개의 테이블을 결합하고 날짜에서 년, 월을 추출하는 것과

 

GROUP BY와 집계 함수를 통해 회원수를 산출하는 쿼리를 작성해 보았습니다!

설명이 어려운 부분 혹은 잘 이해가 안 가는 부분

그리고 더 궁금한 내용이 있다면

언제든지 댓글로 남겨주세요!

빠르게 궁금증을 해결해 드릴게요!

공감과 댓글은 큰 힘이 됩니다!

오늘도 블로그 방문해 주시고

포스팅 읽어주셔서 감사합니다!

 

 

LIST