문제 설명
다음은 어느 의류 쇼핑몰에 가입한 회원 정보를 담은 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문을 작성해주세요. 상품을 구매한 회원의 비율은 소수점 두번째자리에서 반올림하고, 전체 결과는 년을 기준으로 오름차순 정렬해주시고 년이 같다면 월을 기준으로 오름차순 정렬해주세요.
예시
예를 들어 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에서의 유저 수
•
구매비율은 를 소수점으로 표현한 것
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
복사