DB 스터디 3주차

권재현·2021년 6월 16일
0

DB스터디

목록 보기
3/4

3문제(내가 낸 문제는 풀이제외)
테이블은 OT

[3주차 문제2]
판매 직원들별로(사장 제외) 주문 수량이 100개 이상이며, 수익을 낸 주문들의 총 합중에서 가장 큰 값을 작은값으로 나머지값을 구하고(소수점제외)
모든 직원들과 고객들의 핸드폰 번호의 제일 마지막자리가 이전에 구한 값의 차의 숫자중에(1~5자리) 하나라도 포함된 사람들을 출력하시오
-- 출력필드: ID, FIRST_NAME, LAST_NAME, PHONE, EMAIL (EMPLOYEE와 CUSTOMER를 구분하기 위해 ID앞에 EM 또는 CS표시를 하고 CS사람들을 먼저 출력하시오)
EX) 차이가 65432 나오면 휴대전화 마지막 자리가 6, 5, 4, 3, 2 인 사람들을 출력하면 됩니다
CS 72명 / EM 54명 나옵니다

판매 직원들별로(사장 제외) 주문 수량이 100개 이상이며, 수익을 낸 주문들의 총 합중에서 가장 큰 값을 작은값으로 나머지값을 구하고(소수점제외)

SELECT  FLOOR(MOD(MAX(A.RSUM),MIN(A.RSUM))) AS RESULT
FROM (SELECT O.SALESMAN_ID,SUM(OI.QUANTITY * OI.UNIT_PRICE) AS RSUM,
		RANK() OVER(ORDER BY SUM(OI.QUANTITY * OI.UNIT_PRICE) DESC) AS RNK
      FROM ORDERS O INNER JOIN ORDER_ITEMS OI
			    ON O.ORDER_ID = OI.ORDER_ID
			   AND O.STATUS = 'Shipped'
			   AND OI.QUANTITY >= 100
		    INNER JOIN EMPLOYEES E
			    ON O.SALESMAN_ID = E.EMPLOYEE_ID
      GROUP BY O.SALESMAN_ID)A

판매직원,오더상태,총 수익값이 필요해 ORDERS와 ORDER_ITEMS테이블을 조인시키고 조건에 상태 'Shipped', 수량 100개이상을 걸어서 뽑았다.
직원별로 수익 값을 구해야해서 Group by 에 SALESMAN을 넣었다.
수익랭킹은 랭크함수를 이용했다. 그리고 서브쿼리 후 MAX와 MIN를 이용해 나머지값을 구했다.

출력결과

모든 직원들과 고객들의 핸드폰 번호의 제일 마지막자리가 이전에 구한 값의 차의 숫자중에(1~5자리) 하나라도 포함된 사람들을 출력하시오
-- 출력필드: ID, FIRST_NAME, LAST_NAME, PHONE, EMAIL (EMPLOYEE와 CUSTOMER를 구분하기 위해 ID앞에 EM 또는 CS표시를 하고 CS사람들을 먼저 출력하시오)

SELECT *
FROM   (SELECT ('(EM)' ||FIRST_NAME || LAST_NAME),PHONE,SUBSTR(PHONE,-1,1) AS EN, EMAIL FROM EMPLOYEES
        UNION 
        SELECT ('(CS)' ||FIRST_NAME || LAST_NAME),PHONE,SUBSTR(PHONE,-1,1) AS EN, EMAIL FROM CONTACTS ) NA INNER  JOIN (SELECT  FLOOR(MOD(MAX(A.RSUM),MIN(A.RSUM))) AS RESULT
                                                                                                                        FROM (SELECT O.SALESMAN_ID,SUM(OI.QUANTITY * OI.UNIT_PRICE) AS RSUM,
                                                                                                                                RANK() OVER(ORDER BY SUM(OI.QUANTITY * OI.UNIT_PRICE) DESC) AS RNK
                                                                                                                              FROM ORDERS O INNER JOIN ORDER_ITEMS OI
                                                                                                                                                    ON O.ORDER_ID = OI.ORDER_ID
                                                                                                                                                   AND O.STATUS = 'Shipped'
                                                                                                                                                   AND OI.QUANTITY >= 100
                                                                                                                                            INNER JOIN EMPLOYEES E
                                                                                                                                                    ON O.SALESMAN_ID = E.EMPLOYEE_ID
                                                                                                                              GROUP BY O.SALESMAN_ID)A) R
                                                                                                                  ON 1=1
                                                                                                                AND  NA.EN IN( SUBSTR(R.RESULT,0,1),SUBSTR(R.RESULT,1,1),SUBSTR(R.RESULT,2,1))

                                                                                 
;

직원과 고객을 다 출력해야해서 두 테이블에 UNION함수를 이용해 붙이고 그다음 포함된 숫자를 위해서 SUBSTR(자르기 함수)를 이용해 구했다.

정답

[3주차 문제3]
한도가 3500에서 4500사이인 회사들을 구하고/ 웹사이트 이름의 공통된 부분을 제외하고 회사명의 글자길이(공백제외)와 웹사이트명의 글자 길이를 비교해서
회사명의 글자길이가 웹사이트명의 글자길이보다 크면 한도 1.3배, 같으면 1.5배, 작으면 1.7배 해준뒤 전체 회사들의 한도와 비교하여 6위까지와 300백위 밑을 출력하시오
출력필드: 이름, 웹사이트 이름, 크레딧 포인트, 랭킹
EX)https://abcdefg.com -> abcdefg (공통된 부분 제외)

한도가 3500에서 4500사이인 회사들을 구하고/ 웹사이트 이름의 공통된 부분을 제외하고 회사명의 글자길이(공백제외)와 웹사이트명의 글자 길이

SELECT C.NAME,C.WEBSITE,C.CREDIT_LIMIT,REPLACE(C.NAME,' ',''),LENGTH(REPLACE(C.NAME,' ','')) AS CNAME, 
         SUBSTR(SUBSTR(WEBSITE,INSTR(WEBSITE,'.',1)+1),0,INSTR(SUBSTR(WEBSITE,INSTR(WEBSITE,'.',1)+1),'.')-1) AS WNAME
FROM CUSTOMERS C 
WHERE C.CREDIT_LIMIT BETWEEN 3500 AND 4500

한도 3500과 4500은 where 조건에서 처리하고 웹사이트 공통된부분제외를 위해서 substr(자르기함수), instr(위치를 숫자로 리턴)을 이용했다.
회사명 글자길이를 위해서 공백을 replace 이용해 없애고, length를 통해 길이를 구했다

출력결과

회사명의 글자길이가 웹사이트명의 글자길이보다 크면 한도 1.3배, 같으면 1.5배, 작으면 1.7배 해준뒤 전체 회사들의 한도와 비교하여 6위까지와 300백위 밑을 출력하시오

SELECT R3.*
FROM   (SELECT CU.NAME,CU.WEBSITE, CASE WHEN R2.RLIMIT IS NULL
                                            THEN CU.CREDIT_LIMIT
                                            ELSE R2.RLIMIT
                                            END AS LIMIT,
                  RANK() OVER (ORDER BY CASE WHEN R2.RLIMIT IS NULL
                                            THEN CU.CREDIT_LIMIT
                                            ELSE R2.RLIMIT
                                            END DESC) AS RNK
            FROM CUSTOMERS CU LEFT OUTER JOIN (SELECT R.*, CASE WHEN LENGTH(CNAME) > LENGTH(WNAME)
                                                           THEN R.CREDIT_LIMIT * 1.3
                                                           WHEN LENGTH(CNAME) = LENGTH(WNAME)
                                                           THEN R.CREDIT_LIMIT * 1.5
                                                           ELSE R.CREDIT_LIMIT * 1.7
                                                           END AS RLIMIT
                                          FROM (SELECT  NAME,WEBSITE,CREDIT_LIMIT,REPLACE(NAME,' ','') AS CNAME,
                                                    SUBSTR(SUBSTR(WEBSITE,INSTR(WEBSITE,'.',1)+1),0,INSTR(SUBSTR(WEBSITE,INSTR(WEBSITE,'.',1)+1),'.',1)-1) AS WNAME
                                                FROM CUSTOMERS 
                                                WHERE CREDIT_LIMIT BETWEEN 3500 AND 4500) R) R2
                                    ON CU.NAME = R2.NAME ) R3
WHERE R3.RNK  <=6 OR R3.RNK >= 300

case문을 활용해서 한도계산을 해주었고, 마지막 조건은 where에서 처리해주었다.

정답

문제4
17년도 하반기에 고객사가 주문한 주문금액의 합(소수 첫째 자리에서 반올림)을 구하고,
상위 5위의 고객사는 신용한도를 30% 인상하고 그 이외의 고객사는 30%인하하여 신용한도를 기준으로 순위를 구하시오.
출력필드 : CUSTOMER_ID, NAME, SUM(주문금액 합계), CREDIT_LIMIT, RLMIT(신용한도 변동 값), RNK

17년도 하반기에 고객사가 주문한 주문금액의 합(소수 첫째 자리에서 반올림)

SELECT CU.NAME,SUM(OI.QUANTITY*OI.UNIT_PRICE) ,ROUND(SUM(OI.QUANTITY*OI.UNIT_PRICE)) AS OSUM,
        RANK() OVER (ORDER BY ROUND(SUM(OI.UNIT_PRICE),1) DESC) AS RNK
FROM  CUSTOMERS CU INNER JOIN ORDERS O
                           ON CU.CUSTOMER_ID = O.CUSTOMER_ID
                   INNER JOIN ORDER_ITEMS OI
                           ON O.ORDER_ID = OI.ORDER_ID
                          AND O.STATUS NOT IN 'Canceled'
                          AND TO_CHAR(O.ORDER_DATE, 'YY') = 17
                          AND TO_CHAR(O.ORDER_DATE, 'MM') > 6
GROUP BY CU.NAME

17년도와 하반기는 To_CHAR함수를 이용했고, 주문만 들어가야하기에 Not in으로 canceled 을 제외시켰다. 그리고 고객사 별이기에 group by CU.NAME을 해줬다.

출력

상위 5위의 고객사는 신용한도를 30% 인상하고 그 이외의 고객사는 30%인하

SELECT CU2.CUSTOMER_ID,CU2.NAME,S.OSUM,CU2.CREDIT_LIMIT,S.RNK,
        CASE WHEN S.RNK < 6
             THEN CU2.CREDIT_LIMIT *1.3
             ELSE CU2.CREDIT_LIMIT *0.7
             END AS RLIMIT
FROM CUSTOMERS CU2 INNER JOIN (SELECT CU.NAME,SUM(OI.QUANTITY*OI.UNIT_PRICE) ,ROUND(SUM(OI.QUANTITY*OI.UNIT_PRICE)) AS OSUM,
                                        RANK() OVER (ORDER BY ROUND(SUM(OI.UNIT_PRICE),1) DESC) AS RNK
                               FROM  CUSTOMERS CU INNER JOIN ORDERS O
                                                           ON CU.CUSTOMER_ID = O.CUSTOMER_ID
                                                   INNER JOIN ORDER_ITEMS OI
                                                           ON O.ORDER_ID = OI.ORDER_ID
                                                          AND O.STATUS NOT IN 'Canceled'
                                                          AND TO_CHAR(O.ORDER_DATE, 'YY') = 17
                                                          AND TO_CHAR(O.ORDER_DATE, 'MM') > 6
                                GROUP BY CU.NAME) S
                                                           ON CU2.NAME = S.NAME

조건에 맞게 case문을 활용해 계산해 주었다.

출력

신용한도를 기준으로 순위를 구하시오.

SELECT R.*,RANK() OVER(ORDER BY R.RLIMIT DESC ) AS RNKA
FROM (SELECT CU2.CUSTOMER_ID,CU2.NAME,S.OSUM,CU2.CREDIT_LIMIT,S.RNK,
        CASE WHEN S.RNK < 6
             THEN CU2.CREDIT_LIMIT *1.3
             ELSE CU2.CREDIT_LIMIT *0.7
             END AS RLIMIT
     FROM CUSTOMERS CU2 INNER JOIN (SELECT CU2.CUSTOMER_ID,CU2.NAME,S.OSUM,CU2.CREDIT_LIMIT,S.RNK,
        CASE WHEN S.RNK < 6
             THEN CU2.CREDIT_LIMIT *1.3
             ELSE CU2.CREDIT_LIMIT *0.7
             END AS RLIMIT
FROM CUSTOMERS CU2 INNER JOIN (SELECT CU.NAME,SUM(OI.QUANTITY*OI.UNIT_PRICE) ,ROUND(SUM(OI.QUANTITY*OI.UNIT_PRICE)) AS OSUM,
                                        RANK() OVER (ORDER BY ROUND(SUM(OI.UNIT_PRICE),1) DESC) AS RNK
                               FROM  CUSTOMERS CU INNER JOIN ORDERS O
                                                           ON CU.CUSTOMER_ID = O.CUSTOMER_ID
                                                   INNER JOIN ORDER_ITEMS OI
                                                           ON O.ORDER_ID = OI.ORDER_ID
                                                          AND O.STATUS NOT IN 'Canceled'
                                                          AND TO_CHAR(O.ORDER_DATE, 'YY') = 17
                                                          AND TO_CHAR(O.ORDER_DATE, 'MM') > 6
                                GROUP BY CU.NAME) S
                                                           ON CU2.NAME = S.NAME) S
                           ON CU2.NAME = S.NAME) R
;

정답

3주차도 무사히 완료 !!!
이번주는 그전 보다 다양한함수를 이용해서 푸는 문제가 많아서 즐거웠다.

profile
호텔리어 출신 비전공자

0개의 댓글