[스파르타코딩클럽]데이터분석 과정/SQL
[SQL 코드카타] 문제 71~75번 풀이
doo_
2023. 12. 22. 16:46
문제 출처 : 프로그래머스
(71번) 온라인/오프라인 판매데이터 통합하기
SELECT TO_CHAR(SALES_DATE,'YYYY-MM-DD'),
PRODUCT_ID,
USER_ID,
SALES_AMOUNT
FROM (
SELECT *
FROM ONLINE_SALE
UNION
SELECT OFFLINE_SALE_ID,
NULL AS USER_ID,
PRODUCT_ID,
SALES_AMOUNT,
SALES_DATE
FROM OFFLINE_SALE)
WHERE 1=1
TO_CHAR(SALES_DATE,'YYYYMM') = '202203'
ORDER BY SALES_DATE ASC,
PRODUCT_ID ASC,
USER_ID ASC
+) UNION (중복제거) / UNION ALL (중복제거 X) : 합집합
(72번) 조건에 부합하는 중고거래 댓글 구하기
WITH RE_A AS (SELECT BOARD_ID, TITLE
FROM USED_GOODS_BOARD
WHERE TO_CHAR(CREATED_DATE,'YYYYMM') = '202210')
SELECT A.TITLE,
B.BOARD_ID,
B.REPLY_ID,
B.WRITER_ID,
B.CONTENTS,
TO_CHAR(B.CREATED_DATE,'YYYY-MM-DD')
FROM RE_A A,
USED_GOODS_REPLY B
WHERE 1=1
AND A.BOARD_ID = B.BOARD_ID
ORDER BY CREATED_DATE ASC,
TITLE ASC
(73번) 입양 시간 구하기 (2)
- 24시간 칼럼 만들기 : CONNECT BY LEVEL : 연속된 숫자 조회할 때 사용
- 외부조인 이후 NVL(칼럼명, 대체값) 활용하여 널 값 0 채우기
- TO_CHAR 복습
> YYYY : 년 / MM : 월 / DD : 일 / HH24 : 24시간 / HH12 : 12시 / MI : 분 / SS : 초
SELECT A.HOUR, NVL(B.COUNT,0) COUNT
FROM (SELECT LEVEL-1 AS HOUR
FROM DUAL CONNECT BY level <25) A
LEFT JOIN
(SELECT TO_NUMBER(TO_CHAR(datetime, 'hh24')) AS HOUR, COUNT(*) AS COUNT
FROM ANIMAL_OUTS
GROUP BY TO_CHAR(datetime, 'hh24')) B ON A.HOUR = B.HOUR
ORDER BY A.HOUR
> SET함수 활용
(74번) 특정기간 동안 대여 가능한 자동차들의 대여 비용 구하기
> 어려웠던 점 : 왜 NOT IN ( ~~~ WHERE NOT( A OR B)) 부정의 부정을 써야 하는 부분
-- 1) 11월 대여 가능한 CAR_ID 추출 후
-- 2) CAR_TYPE이 '세단'과 'SUV'인 ID 추출
WITH CAR_TYPE_O AS (SELECT CAR_ID, CAR_TYPE, DAILY_FEE
FROM CAR_RENTAL_COMPANY_CAR
WHERE 1=1
AND CAR_ID NOT IN (SELECT DISTINCT CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE 1=1
AND NOT (TO_CHAR(END_DATE, 'YYYYMM') < '20221101'
OR TO_CHAR(START_DATE, 'YYYYMM') > '20221130'
))
AND CAR_TYPE IN ('세단', 'SUV')
)
-- 3) 그 후 대여 기간이 30일 일 때 할인률을 적용하여 계산
SELECT A.CAR_ID, A.CAR_TYPE, ROUND((DAILY_FEE * (100-DISCOUNT_RATE)/100)*30) AS FEE
FROM CAR_TYPE_O A, CAR_RENTAL_COMPANY_DISCOUNT_PLAN B
WHERE 1=1
AND A.CAR_TYPE = B.CAR_TYPE
AND B.DURATION_TYPE = '30일 이상'
AND (30 * DAILY_FEE * (100-DISCOUNT_RATE)/100) >= 500000
AND (30 * DAILY_FEE * (100-DISCOUNT_RATE)/100) < 2000000
ORDER BY FEE DESC, CAR_TYPE ASC, CAR_ID DESC
(75번) 자동차 대여 기록별 대여 금액 구하기
> CASE 절 사용할 때, < 7 THEN X / < 30 THEN '7일 이상' --- 적용이 안 된다...
- 기간을 구해, 조건에 따른 칼럼 추가
WITH RENTAL_DURATION AS
(SELECT C.*, CASE WHEN C.DURATION < 7 THEN '할인 대상 아님'
WHEN C.DURATION < 30 THEN '7일 이상'
WHEN C.DURATION < 90 THEN '30일 이상'
ELSE '90일 이상'
END DURATION_TYPE
FROM (SELECT B.HISTORY_ID,
A.CAR_TYPE,
A.DAILY_FEE,
(B.END_DATE - B.START_DATE + 1) AS DURATION
FROM CAR_RENTAL_COMPANY_CAR A JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY B
ON A.CAR_ID = B.CAR_ID
WHERE CAR_TYPE IN ('트럭')) C
)
-- 그 후 LEFT JOIN 활용해 합친 후 해당 할인 적용
SELECT A.HISTORY_ID,
CASE WHEN DURATION < 7 THEN A.DAILY_FEE*A.DURATION
WHEN DURATION < 30 THEN (100-B.DISCOUNT_RATE)/100*A.DAILY_FEE*A.DURATION
WHEN DURATION < 90 THEN (100-B.DISCOUNT_RATE)/100*A.DAILY_FEE*A.DURATION
ELSE (100-B.DISCOUNT_RATE)/100*A.DAILY_FEE*A.DURATION END FEE
FROM RENTAL_DURATION A LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN B
ON 1=1
AND A.CAR_TYPE = B.CAR_TYPE
AND A.DURATION_TYPE = B.DURATION_TYPE
ORDER BY FEE DESC, A.HISTORY_ID DESC
[ 복습 ]
-- 행의 수 제한
WHERE ROWNUM 비교연산자 n -- 1.
FETCH FRIST n ROWS ONLY -- 2. (마지막 행에)
-- NULL 값 처리
SELECT NVL(COL1, NULL 대체값) FRRM TABLE
* 참고) NULL과의 연산 결과값은 NULL
-- NULLIF는 특정 값을 NULL 처리할 때 사용
SELECT NAME, NULLIF(attr, 'normal') FROM POKEMON
-- COALESCE함수 : 여러 값 중에서 NULL이 아닌 첫 번째 값을 찾을 때 사용.
- DECODE 함수 LIKE CASE문
DECODE(EXPRESSION, VALUE1, RESULT1, VALUE2, RESULT2, ..., DEFAULT_RESULT)