문제 : 상품을 구매한 회원 비율 구하기
문제 설명
다음은 어느 의류 쇼핑몰에 가입한 회원 정보를 담은 USER_INFO 테이블과 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블 입니다. USER_INFO 테이블은 아래와 같은 구조로 되어있으며 USER_ID, GENDER, AGE, JOINED는 각각 회원 ID, 성별, 나이, 가입일을 나타냅니다.
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, 판매량, 판매일을 나타냅니다.
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 테이블에서 2021년에 가입한 전체 회원들 중 상품을 구매한 회원수와 상품을 구매한 회원의 비율(=2021년에 가입한 회원 중 상품을 구매한 회원수 / 2021년에 가입한 전체 회원 수)을 년, 월 별로 출력하는 SQL문을 작성해주세요. 상품을 구매한 회원의 비율은 소수점 두번째자리에서 반올림하고, 전체 결과는 년을 기준으로 오름차순 정렬해주시고 년이 같다면 월을 기준으로 오름차순 정렬해주세요.
문제 접근
SELECT * FROM ( SELECT YEAR(o.sales_date) YEAR ,MONTH(o.sales_date) MONTH, u.USER_ID FROM (SELECT * FROM USER_INFO WHERE JOINED LIKE "2021%") u LEFT JOIN ONLINE_SALE o ON u.USER_ID =o.USER_ID GROUP BY u.USER_ID, YEAR, MONTH) sub
실행 결과
YEAR | MONTH | user_id |
---|---|---|
1 | ||
2022 | 2 | 2 |
2022 | 1 | 2 |
3 | ||
2022 | 1 | 4 |
2022 | 2 | 5 |
6 | ||
2022 | 1 | 7 |
8 | ||
9 | ||
10 | ||
11 | ||
2022 | 1 | 12 |
2022 | 2 | 13 |
2022 | 2 | 14 |
2022 | 1 | 15 |
16 |
이런식으로 연도와 월 별 user_id의 COUNT 를 구했는데
어떻게 하면
각 연도, 월로 group by 해서
user_id 전체 DISTINCT 개수로 나누고싶은데 코드를 어떻게 짜면 좋을까 생각을 해보고 있었다.
내 풀이
SELECT YEAR(sales_date) YEAR, MONTH(sales_date) MONTH, COUNT(DISTINCT o.USER_ID) PURCHASED_USERS, ROUND(COUNT(DISTINCT o.USER_ID) / (SELECT COUNT(*) FROM USER_INFO WHERE JOINED LIKE '2021%') , 1) PUCHASED_RATIO FROM USER_INFO u JOIN ONLINE_SALE o ON u.USER_ID = o.USER_ID WHERE u.JOINED LIKE '2021%' GROUP BY 1,2 ORDER BY 1,2
다른 사람 풀이
CTE 사용
WITH CNT AS( SELECT COUNT(DISTINCT USER_ID) NUM FROM USER_INFO WHERE YEAR(JOINED)='2021' )
SELECT YEAR(SALES_DATE) YEAR,
MONTH(SALES_DATE) MONTH,
COUNT(DISTINCT USER_ID) PURCHASED_USERS,
ROUND(COUNT(DISTINCT USER_ID)/(SELECT COUNT(USER_ID) FROM USER_INFO WHERE YEAR(JOINED)='2021'),1) PURCHASED_RATIO
FROM ONLINE_SALE
JOIN USER_INFO USING(USER_ID)
WHERE YEAR(JOINED)='2021'
GROUP BY 1,2
ORDER BY 1,2
with을 사용한 풀이
>
```sql
WITH JOINED2021 AS (
SELECT *
FROM USER_INFO
WHERE YEAR(JOINED) = '2021'
)
SELECT YEAR(B.SALES_DATE) YEAR, MONTH(B.SALES_DATE) MONTH,
COUNT(DISTINCT B.USER_ID) PURCHASED_USERS,
ROUND(COUNT(DISTINCT B.USER_ID) / (SELECT COUNT(*) FROM JOINED2021), 1) PURCHASED_RATIO
FROM JOINED2021 A
INNER JOIN ONLINE_SALE B ON A.USER_ID = B.USER_ID
GROUP BY YEAR, MONTH
ORDER BY YEAR, MONTH
쉬운 문제였지만 너무 어렵게 생각했던 것 같다.
SLECT 안에 SELECT 를 사용해서 테이블을 두번 불러와도 되는데
너무 JOIN 과정에서 해결하려고 하다보니 어려워졌던 부분이었다.