[SELECT] 오프라인/온라인 판매 데이터 통합하기

2024. 9. 20. 18:00SQL 고득점 Kit/SELECT

https://school.programmers.co.kr/learn/courses/30/lessons/131537

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr


문제 설명
다음은 어느 의류 쇼핑몰의 온라인 상품 판매 정보를 담은 ONLINE_SALE 테이블과 오프라인 상품 판매 정보를 담은 OFFLINE_SALE 테이블 입니다. 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 조합에 대해서는 하나의 판매 데이터만 존재합니다.

OFFLINE_SALE 테이블은 아래와 같은 구조로 되어있으며 OFFLINE_SALE_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE는 각각 오프라인 상품 판매 ID, 상품 ID, 판매량, 판매일을 나타냅니다.

Column name Type Nullable
OFFLINE_SALE_ID INTEGER FALSE
PRODUCT_ID INTEGER FALSE
SALES_AMOUNT INTEGER FALSE
SALES_DATE DATE FALSE


동일한 날짜, 상품 ID 조합에 대해서는 하나의 판매 데이터만 존재합니다.


문제
ONLINE_SALE 테이블과 OFFLINE_SALE 테이블에서 2022년 3월의 오프라인/온라인 상품 판매 데이터의 판매 날짜, 상품ID, 유저ID, 판매량을 출력하는 SQL문을 작성해주세요. OFFLINE_SALE 테이블의 판매 데이터의 USER_ID 값은 NULL 로 표시해주세요. 결과는 판매일을 기준으로 오름차순 정렬해주시고 판매일이 같다면 상품 ID를 기준으로 오름차순, 상품ID까지 같다면 유저 ID를 기준으로 오름차순 정렬해주세요.


예시
예를 들어 ONLINE_SALE 테이블이 다음과 같고

ONLINE_SALE_ID USER_ID PRODUCT_ID SALES_AMOUNT SALES_DATE
1 1 3 2 2022-02-25
2 4 4 1 2022-03-01
4 2 2 2 2022-03-02
3 6 3 3 2022-03-02
5 5 5 1 2022-03-03
6 5 7 1 2022-04-06


OFFLINE_SALE 테이블이 다음과 같다면

OFFLINE_SALE_ID PRODUCT_ID SALES_AMOUNT SALES_DATE
1 1 2 2022-02-21
4 1 2 2022-03-01
3 3 3 2022-03-01
2 4 1 2022-03-01
5 2 1 2022-03-03
6 2 1 2022-04-01


각 테이블의 2022년 3월의 판매 데이터를 합쳐서, 정렬한 결과는 다음과 같아야 합니다.

SALES_DATE PRODUCT_ID USER_ID SALES_AMOUNT
2022-03-01 1 NULL 2
2022-03-01 3 NULL 3
2022-03-01 4 NULL 1
2022-03-01 4 4 1
2022-03-02 2 2 2
2022-03-02 3 6 3
2022-03-03 2 NULL 1
2022-03-03 5 5 1

2022년 3월의 오프라인/온라인 상품 판매 데이터의 판매 날짜, 상품ID, 유저ID, 판매량을 출력하는 문제입니다.

특징이라면 오프라인 상품 판매 데이터에는 유저ID를 NULL로 처리한다는 점이네요.


문제가 특이한 게, 오프라인에는 2022년 3월의 데이터가 없습니다. 정합성 검증을 못한다는 뜻이죠.

그리고 예시에서는 날짜가 년 - 월 - 일 순으로만 적혀있지만, 실제로는 여기에 시간:분:초까지 다 포함되어 있습니다.

날짜를 바꾸기도 해야되는데 설명에는 없네요. 아무튼 잊지 않으시면 됩니다.

 

저는 UNION 함수를 사용해 온라인과 오프라인을 하나의 테이블로 합치고, 그 테이블에서 출력하는 것으로 코드를 작성했습니다.

UNION 함수만 사용해서 표현해도 되기는 하는데, 제 취향이 이쪽이라서 이렇게 풀었습니다.

 

오프라인에서 처리해야 할 중요한 점은 USER_ID를 NULL로 처리하는 점입니다.

저는 COALESCE 함수를 사용해, 값이 없다면 NULL을 처리하도록 설정해 새로운 열을 USER_ID라는 이름으로 생성했습니다.

그 다음, 온라인 테이블과 합쳐서 열을 맞춰주었고요.

 

정답 코드를 작성해보겠습니다.

  SELECT DATE_FORMAT(SALES_DATE, '%Y-%m-%d') AS SALES_DATE, PRODUCT_ID, USER_ID, SALES_AMOUNT
    FROM (SELECT USER_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE
            FROM ONLINE_SALE
           WHERE YEAR(SALES_DATE) = 2022
                 AND MONTH(SALES_DATE) = 3
           UNION
          SELECT COALESCE(NULL) AS USER_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE
            FROM OFFLINE_SALE
           WHERE YEAR(SALES_DATE) = 2022
             AND MONTH(SALES_DATE) = 3) SALE
ORDER BY SALES_DATE ASC, PRODUCT_ID ASC, USER_ID ASC

 

이제 보니까 WHERE 조건절은 아래로 빼도 상관이 없을 것 같습니다.

SELECT DATE_FORMAT(SALES_DATE, '%Y-%m-%d') AS SALES_DATE, PRODUCT_ID, USER_ID, SALES_AMOUNT
    FROM (SELECT USER_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE
            FROM ONLINE_SALE
           UNION
          SELECT COALESCE(NULL) AS USER_ID, PRODUCT_ID, SALES_AMOUNT, SALES_DATE
            FROM OFFLINE_SALE) SALE
   WHERE YEAR(SALES_DATE) = 2022
         AND MONTH(SALES_DATE) = 3
ORDER BY SALES_DATE ASC, PRODUCT_ID ASC, USER_ID ASC

 

FROM 절에 나오는 서브쿼리는 인라인 뷰라고 하는데요, 해당 뷰는 따로 이름을 지정해줘야 합니다.

저는 SALE이라는 이름을 지정해주었습니다.