상품을 구매한 회원 비율 구하기
JOIN
상품을 구매한 회원 비율 구하기
문제 설명
다음은 어느 의류 쇼핑몰에 가입한 회원 정보를 담은 USER_INFO 테이블과 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블입니다.
USER_INFO 테이블
Column name | Type | Nullable | Description |
---|---|---|---|
USER_ID | INTEGER | FALSE | 회원 ID |
GENDER | TINYINT(1) | TRUE | 성별 (0: 남자, 1: 여자) |
AGE | INTEGER | TRUE | 나이 |
JOINED | DATE | FALSE | 가입일 |
GENDER 컬럼은 비어있거나 0 또는 1의 값을 가지며 0인 경우 남자를, 1인 경우는 여자를 나타냅니다.
ONLINE_SALE 테이블
Column name | Type | Nullable | Description |
---|---|---|---|
ONLINE_SALE_ID | INTEGER | FALSE | 온라인 상품 판매 ID |
USER_ID | INTEGER | FALSE | 회원 ID |
PRODUCT_ID | INTEGER | FALSE | 상품 ID |
SALES_AMOUNT | INTEGER | FALSE | 판매량 |
SALES_DATE | DATE | FALSE | 판매일 |
동일한 날짜, 회원 ID, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.
문제
USER_INFO 테이블과 ONLINE_SALE 테이블에서 2021년에 가입한 전체 회원들 중 상품을 구매한 회원수와 상품을 구매한 회원의 비율(= 2021년에 가입한 회원 중 상품을 구매한 회원수 / 2021년에 가입한 전체 회원 수)을 년, 월 별로 출력하는 SQL문을 작성해주세요. 상품을 구매한 회원의 비율은 소수점 두번째자리에서 반올림하고, 전체 결과는 년을 기준으로 오름차순 정렬해주시고 년이 같다면 월을 기준으로 오름차순 정렬해주세요.
풀이 과정
- 조건 확인
- 2021년에 가입한 회원만 대상으로 계산해야 함
- 년, 월별로 그룹화하여 월별로 상품을 구매한 회원 수와 구매 비율을 계산
- 회원과 판매 데이터를 결합 (LEFT JOIN)
- 두 테이블을
USER_ID
를 기준으로 조인 - LEFT JOIN 사용 이유 : 모든 회원 정보 기준으로 판매 정보를 결합해야 하므로
- 두 테이블을
- 상품 구매 여부 확인
- 특정 연도, 월에 동일한 회원이 여러 번 구매했더라도 중복 카운트하면 안 되므로
- 각 기간별로 고유한
USER_ID
를 세기 위해 COUNT(DISTINCT) 이렇게 하자
- 2021년에 가입한 전체 회원 수 계산
- 서브쿼리로 전체 회원 수를 가져와서 나중에 구매 비율을 계산하는 데 써야겠군
- 구매 비율 계산
- 구매 비율은 해당 월에 상품을 구매한 회원의 수 / 전체 회원 수로 계산
- 소수점 두 번째 자리에서 반올림 해야하니 ROUND 사용하자
- 결과 정렬
- 정렬 기준에 따라 ORDER BY로 결과 정렬
- 년도와 월 기준으로 ASC 정렬
- 정렬 기준에 따라 ORDER BY로 결과 정렬
- 교훈
- DISTINCT와 GROUP BY를 같이 사용해서 중복을 방지.. 년도, 월별로 GROUP BY 하는 쿼리… 천재적이다. 어떻게 이런 쿼리 문제가 있지. 새로워서 끄암짝 놀랐다.
- GROUP BY 한 것을 ORDER BY…. 진짜 천재인가. 나는 아직 부족하다.. 계속 나아가자.
정답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SELECT
EXTRACT(YEAR FROM O.SALES_DATE) AS YEAR,
EXTRACT(MONTH FROM O.SALES_DATE) AS MONTH,
COUNT(DISTINCT O.USER_ID) AS PURCHASED_USERS,
ROUND(COUNT(DISTINCT O.USER_ID) /
(SELECT COUNT(*)
FROM USER_INFO
WHERE EXTRACT(YEAR FROM JOINED) = 2021), 1) AS PURCHASED_RATIO
FROM
ONLINE_SALE O
INNER JOIN
USER_INFO U ON O.USER_ID = U.USER_ID
WHERE
EXTRACT(YEAR FROM U.JOINED) = 2021
GROUP BY
EXTRACT(YEAR FROM O.SALES_DATE),
EXTRACT(MONTH FROM O.SALES_DATE)
ORDER BY
YEAR,
MONTH;
Tip
- 구매 비율 = 해당 월에 상품을 구매한 회원의 수 / 전체 회원
- EXTRACT(YEAR FROM
DATE타입컬럼값
), EXTRACT(MONTH FROMDATE타입컬럼값
) 사용하여 년도와 월별 데이터 그룹화- 소수점 두 번째 자리에서 반올림하기 위해 ROUND() 함수 사용 (둘쨋자리에서 반올림 해야하니 ROUND(컬렴명, 1) <- 이렇게 함수 사용해야함)
- TO_CHAR(
DATE타입컬럼값
, ‘YYYY’) 사용하게되면 STRING 반환하므로 ex) 2025-02-12 일 때 STRING의 ‘02’ 반환!- EXTRACT(MONTH FROM
DATE타입컬럼값
) 사용하게되면 NUMBER 반환하므로 ex) 2025-02-12 일 때 NUMBER의 ‘02’ 반환!
SQL Dialect Used: Oracle
개념 확인
- INNER JOIN
- 두 테이블의 공통된 컬럼을 기준으로 데이터를 연결
- 양쪽 테이블 모두에 일치하는 행만 결과에 포함됨
- EXTRACT() 함수
- 날짜 데이터에서 특정 연도나 월을 추출하는 데 사용
- 오라클과 MySQL에서 모두 지원됨
- EXTRACT(YEAR FROM
DATE타입컬럼값
) 형태로 사용- 추출 가능한 값:
- 연도: YEAR
- 월: MONTH
- 일: DAY
- 시간: HOUR
- 분: MINUTE
- 초: SECOND
- COUNT(DISTINCT)
- 특정 컬럼의 고유한 값(중복 제거된 값)의 개수를 셀 때 사용
- ROUND() 함수
- 소수점 이하의 값을 반올림하는 데 사용
- 기본 구문은
ROUND(
컬럼명 or 숫자, 자릿수)
이며, 반올림하고자 하는 소수 자릿수를 명시함
Useful link
This post is licensed under Park Juyoung by the author.