Search

상품을 구매한 회원 비율 구하기

대분류
기타
소분류
코딩테스트
난이도
Level 5
문제 주소
https://school.programmers.co.kr/learn/courses/30/lessons/131534
테스트사이트
프로그래머스
최종 편집 일시
2024/10/29 07:43
생성 일시
2024/08/26 07:35
13 more properties

문제 설명

다음은 어느 의류 쇼핑몰에 가입한 회원 정보를 담은 USER_INFO 테이블과 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블 입니다. USER_INFO 테이블은 아래와 같은 구조로 되어있으며 USER_IDGENDERAGEJOINED는 각각 회원 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_IDUSER_IDPRODUCT_IDSALES_AMOUNTSALES_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문을 작성해주세요. 상품을 구매한 회원의 비율은 소수점 두번째자리에서 반올림하고, 전체 결과는 년을 기준으로 오름차순 정렬해주시고 년이 같다면 월을 기준으로 오름차순 정렬해주세요.

예시

예를 들어 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
2022-01-09
6
1
33
2022-02-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
2021년에 가입한 회원은 USER_ID가 1, 2, 3, 4 인 회원들로 총 4명 입니다. 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
5
2
31
2
2022-02-09
그러므로 년, 월 별로 상품을 구매한 회원수와 상품을 구매한 회원의 비율을 구하고 결과를 정렬하면 다음과 같아야 합니다.
YEAR
MONTH
PURCHASED_USERS
PUCHASED_RATIO
2022
1
2
0.5
2022
2
1
0.3

문제 풀이

1.
FROM
USER_INFO 테이블에서 가져오는데
2.
JOIN
ONLINE_SALE 테이블과 조인을 해서 가져와야 한다.
중복되는 키는 USER_ID이므로 해당 키를 기준으로 조인
2021년에 가입한 전체 회원들 중 상품을 구매한 회원수니 구매하지 않은 고객을 제외하는 INNER JOIN을 사용
3.
WHERE
JOINED의 연도가 2021년인 사용자만 가져오기
4.
GROUP BY
연도와 월별로 결과를 그룹화
5.
SELECT
연도, 월, 구매회원수, 구매비율을 찾아서 가져온다.
구매회원수는 중복제거한 ONLINE_SALE에서의 유저 수
구매비율은 구매회원수(SaleCount)/JOINED의연도가2021년인모든사용자수구매회원수(Sale Count) / JOINED의 연도가2021년인 모든 사용자 수를 소수점으로 표현한 것
6.
ORDER BY
가져온 걸 year, month순으로 정렬한다.

코드

FROM
SELECT * FROM USER_INFO AS c1 -- 사용자 정보가 있는 USER_INFO 테이블을 c1이라는 별칭으로 사용 INNER JOIN ONLINE_SALE AS c2 -- 판매 기록이 있는 ONLINE_SALE 테이블을 c2라는 별칭으로 사용 ON c1.USER_ID = c2.USER_ID -- USER_ID를 기준으로 두 테이블을 조인하여 사용자와 그들의 판매 기록을 연결
SQL
복사
WHERE
SELECT * FROM USER_INFO AS c1 -- 사용자 정보가 있는 USER_INFO 테이블을 c1이라는 별칭으로 사용 INNER JOIN ONLINE_SALE AS c2 -- 판매 기록이 있는 ONLINE_SALE 테이블을 c2라는 별칭으로 사용 ON c1.USER_ID = c2.USER_ID -- USER_ID를 기준으로 두 테이블을 조인하여 사용자와 그들의 판매 기록을 연결 WHERE 1=1 AND date_format(c1.JOINED, '%Y')='2021' -- JOINED의 연도가 2021년인 사용자만 선택
SQL
복사
GROUP BY
SELECT * FROM USER_INFO AS c1 -- 사용자 정보가 있는 USER_INFO 테이블을 c1이라는 별칭으로 사용 INNER JOIN ONLINE_SALE AS c2 -- 판매 기록이 있는 ONLINE_SALE 테이블을 c2라는 별칭으로 사용 ON c1.USER_ID = c2.USER_ID -- USER_ID를 기준으로 두 테이블을 조인하여 사용자와 그들의 판매 기록을 연결 WHERE 1=1 AND date_format(c1.JOINED, '%Y')='2021' -- JOINED의 연도가 2021년인 사용자만 선택 GROUP BY year, month -- 연도와 월별로 결과를 그룹화하여 각 월의 데이터로 묶음
SQL
복사
SELECT
SELECT date_format(c2.SALES_DATE, '%Y') AS year, -- SALES_DATE에서 연도만 추출하여 'year'라는 별칭으로 선택 date_format(c2.SALES_DATE, '%m') AS month, -- SALES_DATE에서 월만 추출하여 'month'라는 별칭으로 선택 COUNT(DISTINCT c2.USER_ID) AS 'Sale Count', -- 중복되지 않은 USER_ID를 세어 한 달 동안 판매를 한 사용자 수를 'Sale Count'로 표시 ROUND( COUNT(DISTINCT c2.USER_ID) / -- 한 달 동안 판매를 한 사용자 수를 계산 ( SELECT COUNT(USER_ID) FROM USER_INFO WHERE 1=1 AND YEAR(JOINED)='2021' -- JOINED의 연도가 2021년인 모든 사용자 수를 계산 ), 1 ) AS 'Sale Percent' -- 한달 동안 판매를 한 사용자 수를 전체 2021년 가입자 수로 나누어 'Sale Percent'로 표시 -- (소수점 첫째 자리에서 반올림, 소수점으로 표시) FROM USER_INFO AS c1 -- 사용자 정보가 있는 USER_INFO 테이블을 c1이라는 별칭으로 사용 INNER JOIN ONLINE_SALE AS c2 -- 판매 기록이 있는 ONLINE_SALE 테이블을 c2라는 별칭으로 사용 ON c1.USER_ID = c2.USER_ID -- USER_ID를 기준으로 두 테이블을 조인하여 사용자와 그들의 판매 기록을 연결 WHERE 1=1 AND date_format(c1.JOINED, '%Y')='2021' -- JOINED의 연도가 2021년인 사용자만 선택 GROUP BY year, month -- 연도와 월별로 결과를 그룹화하여 각 월의 데이터로 묶음
SQL
복사
ORDER BY
SELECT date_format(c2.SALES_DATE, '%Y') AS year, -- SALES_DATE에서 연도만 추출하여 'year'라는 별칭으로 선택 date_format(c2.SALES_DATE, '%m') AS month, -- SALES_DATE에서 월만 추출하여 'month'라는 별칭으로 선택 COUNT(DISTINCT c2.USER_ID) AS 'Sale Count', -- 중복되지 않은 USER_ID를 세어 한 달 동안 판매를 한 사용자 수를 'Sale Count'로 표시 ROUND( COUNT(DISTINCT c2.USER_ID) / -- 한 달 동안 판매를 한 사용자 수를 계산 ( SELECT COUNT(USER_ID) FROM USER_INFO WHERE 1=1 AND YEAR(JOINED)='2021' -- JOINED의 연도가 2021년인 모든 사용자 수를 계산 ), 1 ) AS 'Sale Percent' -- 한달 동안 판매를 한 사용자 수를 전체 2021년 가입자 수로 나누어 'Sale Percent'로 표시 -- (소수점 첫째 자리에서 반올림, 소수점으로 표시) FROM USER_INFO AS c1 -- 사용자 정보가 있는 USER_INFO 테이블을 c1이라는 별칭으로 사용 INNER JOIN ONLINE_SALE AS c2 -- 판매 기록이 있는 ONLINE_SALE 테이블을 c2라는 별칭으로 사용 ON c1.USER_ID = c2.USER_ID -- USER_ID를 기준으로 두 테이블을 조인하여 사용자와 그들의 판매 기록을 연결 WHERE 1=1 AND date_format(c1.JOINED, '%Y')='2021' -- JOINED의 연도가 2021년인 사용자만 선택 GROUP BY year, month -- 연도와 월별로 결과를 그룹화하여 각 월의 데이터로 묶음 ORDER BY year, month; -- 연도와 월별로 결과를 오름차순으로 정렬하여 시간순으로 정렬
SQL
복사

진짜

WITH FILTERED_USERS AS ( SELECT USER_ID # 3 FROM USER_INFO # 1 WHERE 1=1 # 2 AND JOINED >= '2021-01-01' AND JOINED <= '2021-12-31' ), EMP AS ( SELECT # 5 USER_ID , SALES_DATE , ROW_NUMBER() OVER (PARTITION BY USER_ID , YEAR(SALES_DATE) , MONTH(SALES_DATE) ORDER BY SALES_DATE) AS RN FROM ONLINE_SALE # 4 ), REPRESENTATIVE_SALE AS ( SELECT # 8 USER_ID , YEAR(SALES_DATE) AS YEAR , MONTH(SALES_DATE) AS MONTH FROM EMP # 6 WHERE RN = 1 # 7 ) SELECT # 12 RS.YEAR AS YEAR , RS.MONTH AS MONTH , COUNT(RS.USER_ID) AS PURCHASED_USERS , ROUND(COUNT(RS.USER_ID) / (SELECT COUNT(*) FROM FILTERED_USERS), 1) AS PURCHASED_RATIO FROM FILTERED_USERS AS FU # 9 JOIN REPRESENTATIVE_SALE AS RS # 10 ON FU.USER_ID = RS.USER_ID GROUP BY RS.YEAR, RS.MONTH # 11 ORDER BY RS.YEAR, RS.MONTH # 13 ;
SQL
복사