학원/수업 기록

데이터베이스 어려운 문제.. 집계 함수에 대해 이해하기.. - OT

60cod 2022. 7. 15. 14:55

1. 각 연도 별 월 별 최고 인기 판매 상품(판매량이 많다)을 구하시오.

-- 내가 푼 것
SELECT E.YM, P.PRODUCT_NAME, E.QUANTITY
FROM (SELECT TO_CHAR(O.ORDER_DATE, 'YYYY-MM') AS YM,
                OI.PRODUCT_ID, 
                SUM(OI.QUANTITY) AS QUANTITY,
                RANK() OVER(PARTITION BY TO_CHAR(O.ORDER_DATE, 'YYYY-MM')
                            ORDER BY SUM(OI.QUANTITY) DESC) AS RNK
        FROM ORDERS O INNER JOIN ORDER_ITEMS OI
                              ON O.ORDER_ID = OI.ORDER_ID
        WHERE O.STATUS != 'Canceled'
        GROUP BY TO_CHAR(O.ORDER_DATE, 'YYYY-MM'), OI.PRODUCT_ID) E
            INNER JOIN PRODUCTS P
                    ON E.PRODUCT_ID = P.PRODUCT_ID
WHERE E.RNK = 1
;
-- 강사님 코드
-- DESCRIPTION은 그냥 강사님이 같이 뽑아보고 싶어서 하신 거래
SELECT O.YM, O.PRODUCT_NAME, 
        SUBSTR(O.DESCRIPTION, 1, 10) || '...' AS DESCRIPT, 
        O.QUANTITY
FROM (SELECT TO_CHAR(O.ORDER_DATE, 'YYYYMM')AS YM, 
      P.PRODUCT_NAME, P.DESCRIPTION,
      SUM(OI.QUANTITY) AS QUANTITY,
      RANK() OVER(PARTITION BY TO_CHAR(O.ORDER_DATE, 'YYYYMM')
                  ORDER BY SUM(OI.QUANTITY) DESC) AS RNK
      FROM ORDERS O INNER JOIN ORDER_ITEMS OI
                            ON O.ORDER_ID = OI.ORDER_ID
                    INNER JOIN PRODUCTS P
                            ON OI.PRODUCT_ID = P.PRODUCT_ID
      WHERE O.STATUS != 'Canceled'
      GROUP BY TO_CHAR(O.ORDER_DATE, 'YYYYMM'), P.PRODUCT_NAME, P.DESCRIPTION)O
WHERE O.RNK = 1
ORDER BY O.YM ASC
;

 

 

 

2. 고객사 별 구매 선호 제품(주문량X 주문건수O) 카테고리 1, 2위를 구하시오.

중요한 건 주문건수!

ORDER 하나 당 하나씩 카운트 해야 하는 것.

-- 1차.. Aflac 회사로 제한해서 작게 해봄..
SELECT E.NAME, E.CATEGORY_NAME, E.CNT, E.RNK
FROM (SELECT E.NAME, E.CATEGORY_NAME,
                COUNT(*) AS CNT,
                RANK() OVER(ORDER BY COUNT(*) DESC) AS RNK
        FROM (SELECT DISTINCT C.NAME, O.ORDER_ID, P.CATEGORY_ID, PC.CATEGORY_NAME
                FROM ORDERS O INNER JOIN ORDER_ITEMS OI
                                      ON O.ORDER_ID = OI.ORDER_ID
                                      AND O.STATUS != 'Canceled'
                                      AND O.CUSTOMER_ID = '16'
                              INNER JOIN PRODUCTS P
                                      ON OI.PRODUCT_ID = P.PRODUCT_ID
                              INNER JOIN PRODUCT_CATEGORIES PC
                                      ON P.CATEGORY_ID = PC.CATEGORY_ID
                              INNER JOIN CUSTOMERS C
                                      ON O.CUSTOMER_ID = C.CUSTOMER_ID) E
        GROUP BY E.NAME, E.CATEGORY_NAME) E
WHERE E.RNK IN (1, 2)
;

처음에 강사님꺼 출력 결과 보고 회사 하나(CUSTOMER_ID = 16) 찍어서 차근차근 뽑아서 접근해봤는데

위와 같이 하니 잘 나왔음!

근데 여기서 진행을 못하는 거다....

INNER JOIN에서 저 고객사ID 16 조건 하나만 지우면 되는 줄 알았는데 지우면 데이터가 이상해짐 ㅠㅠ

그래서 엄청 많이 고치고 시도하고 계속 고민했는데 안 돼서 정말 힘들었는데..결국 풀어냄!!

-> 저 조건(고객사)을 없애야 하는데 지우니 이상해진다면 그 조건 기준(고객사)을 추가해주면 되는 거 아닐까 해서 랭크의 PARTITION BY 로 CUSTOMER 기준(CUSTOMER의 이름)을 넣었음.

그랬더니 성공~~!!!!

-- 내가 푼 것
SELECT E.NAME, E.CATEGORY_NAME, E.CNT, E.RNK
FROM (SELECT E.NAME, E.CATEGORY_NAME,
                COUNT(*) AS CNT,
                RANK() OVER(PARTITION BY E.NAME
                            ORDER BY COUNT(*) DESC) AS RNK
        FROM (SELECT DISTINCT C.NAME, O.ORDER_ID, P.CATEGORY_ID, PC.CATEGORY_NAME
                FROM ORDERS O INNER JOIN ORDER_ITEMS OI
                                      ON O.ORDER_ID = OI.ORDER_ID
                                      AND O.STATUS != 'Canceled'
                              INNER JOIN PRODUCTS P
                                      ON OI.PRODUCT_ID = P.PRODUCT_ID
                              INNER JOIN PRODUCT_CATEGORIES PC
                                      ON P.CATEGORY_ID = PC.CATEGORY_ID
                              INNER JOIN CUSTOMERS C
                                      ON O.CUSTOMER_ID = C.CUSTOMER_ID) E
        GROUP BY E.NAME, E.CATEGORY_NAME) E
WHERE E.RNK IN (1, 2)
;
-- 강사님 쿼리
SELECT C.NAME, PC.CATEGORY_NAME, O.CNT, O.RNK
FROM (SELECT O.CUSTOMER_ID, O.CATEGORY_ID, COUNT(*) AS CNT,
             RANK() OVER(PARTITION BY O.CUSTOMER_ID
                         ORDER BY COUNT(*) DESC) AS RNK
      FROM (SELECT DISTINCT O.ORDER_ID, O.CUSTOMER_ID, P.CATEGORY_ID
            FROM ORDERS O INNER JOIN ORDER_ITEMS OI
                                  ON O.ORDER_ID = OI.ORDER_ID
                          INNER JOIN PRODUCTS P
                                  ON OI.PRODUCT_ID = P.PRODUCT_ID
            WHERE O.STATUS != 'Canceled')O
      GROUP BY O.CUSTOMER_ID, O.CATEGORY_ID)O
INNER JOIN CUSTOMERS C
        ON O.CUSTOMER_ID = C.CUSTOMER_ID
INNER JOIN PRODUCT_CATEGORIES PC
        ON O.CATEGORY_ID = PC.CATEGORY_ID
WHERE O.RNK IN (1,2)
ORDER BY C.NAME ASC, O.RNK ASC
;