WITH y_2021 AS (
select *
from user_info
where joined between '2021-01-01' and '2021-12-31'
group by user_id
)
SELECT DATE_FORMAT(sales_date, '%Y') YEAR,
DATE_FORMAT(sales_date, '%m') MONTH,
count(distinct y.user_id) PURCHASED_USERS,
(count(distinct os.user_id) / count(*))*100 AS PURCHASED_RATIO
FROM y_2021 as y
JOIN online_sale as os ON y.user_id = os.user_id
GROUP BY 1, 2
ORDER BY YEAR ASC, MONTH ASC
🔍 실행 결과
무언가 "상품을 구매한 회원 비율"을 구하는 것에서 문제가 생긴 듯 하다. 🚨 문제점 - 구매한 회원의 비율의 논리적 구조가 잘못되었음 - purchased_ratio(비율)에서는 정답예시와 같이 나와야 하므로, *100 을 하면 안됨.
정답 코드
1. CROSS JOIN 을 사용한 방법
WITH y_2021 AS ( -- 2021년 가입한 회원 목록
SELECT user_id
FROM user_info
WHERE joined BETWEEN '2021-01-01' AND '2021-12-31'
),
count_2021 AS ( -- 2021년 가입한 회원 수
SELECT COUNT(*) AS total_users
FROM y_2021
)
SELECT
YEAR(os.sales_date) AS YEAR,
MONTH(os.sales_date) AS MONTH,
COUNT(DISTINCT os.user_id) AS PURCHASED_USERS,
ROUND(COUNT(DISTINCT os.user_id) / c.total_users, 1) AS PURCHASED_RATIO
FROM online_sale os
JOIN y_2021 y ON os.user_id = y.user_id
CROSS JOIN count_2021 c -- CROSS JOIN 사용
GROUP BY YEAR, MONTH, c.total_users
ORDER BY YEAR, MONTH;
2. 서브쿼리를 사용한 방법 ⭐️⭐️⭐️
WITH y_2021 AS (
SELECT user_id
FROM user_info
WHERE joined BETWEEN '2021-01-01' AND '2021-12-31'
)
SELECT
YEAR(os.sales_date) AS YEAR,
MONTH(os.sales_date) AS MONTH,
COUNT(DISTINCT os.user_id) AS PURCHASED_USERS,
ROUND(
COUNT(DISTINCT os.user_id) / (SELECT COUNT(*) FROM y_2021),
2
) AS PURCHASED_RATIO
FROM online_sale os
JOIN y_2021 y ON os.user_id = y.user_id
GROUP BY YEAR, MONTH
ORDER BY YEAR, MONTH;
3. 또 다른 풀이법 : CROSS JOIN의 다른 표현법
WITH TOTAL AS ( -- 2021년 가입자 수
SELECT COUNT(*) AS CNT
FROM USER_INFO A
WHERE A.JOINED LIKE '2021%'
)
SELECT YEAR(B.SALES_DATE) AS YEAR
, MONTH(B.SALES_DATE) AS MON
, COUNT(DISTINCT B.USER_ID) AS PURCHASED_USERS
, ROUND((COUNT(DISTINCT B.USER_ID)/T.CNT), 1) AS PUCHASED_RATIO
FROM ONLINE_SALE B
, USER_INFO A
, TOTAL T
WHERE B.USER_ID = A.USER_ID
AND A.JOINED LIKE '2021%'
GROUP BY YEAR, MON
ORDER BY YEAR, MON
틈새 문법
1) CROSS JOIN
▷ 언제사용? "모든 조합을 한 번에 만들고 싶을 때" 또는 "한 테이블의 상수(값 1개)를 모든 행에 붙이고 싶을 때" 유용