Data miner/Developer

[프로그래머스] 특정 기간동안 대여 가능한 자동차들의 대여비용 구하기

carayoon 2023. 6. 29. 23:56
728x90


문제 출처 : https://school.programmers.co.kr/learn/courses/30/lessons/157339

 

프로그래머스

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

programmers.co.kr

 

CAR_RENTAL_COMPANY_CAR 테이블과 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블과CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블에서 자동차 종류가 '세단' 또는 'SUV' 인 자동차 중 2022년 11월 1일부터 2022년 11월 30일까지 대여 가능하고 30일간의 대여 금액이 50만원 이상 200만원 미만인 자동차에 대해서 자동차 ID, 자동차 종류, 대여 금액(컬럼명: FEE) 리스트를 출력하는 SQL문을 작성해주세요. 결과는 대여 금액을 기준으로 내림차순 정렬하고, 대여 금액이 같은 경우 자동차 종류를 기준으로 오름차순 정렬, 자동차 종류까지 같은 경우 자동차 ID를 기준으로 내림차순 정렬해주세요.

 

WITH NOT_RENT AS 
    (
    SELECT RENT.CAR_ID
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY AS RENT
    WHERE RENT.END_DATE >= '2022-11-01' AND RENT.START_DATE < '2022-12-01'
    ),
    
    DIS_RATE AS 
    (SELECT DIS.CAR_TYPE, DIS.DURATION_TYPE, (100-DIS.DISCOUNT_RATE)*0.01 AS DISCOUNT_RATE
     FROM CAR_RENTAL_COMPANY_DISCOUNT_PLAN AS DIS
     WHERE DIS.DURATION_TYPE = '30일 이상')


SELECT *
FROM
    (
    SELECT CAR.CAR_ID, CAR.CAR_TYPE,
           CEILING(CAR.DAILY_FEE*DIS_RATE.DISCOUNT_RATE*30) AS FEE
    FROM CAR_RENTAL_COMPANY_CAR AS CAR
    LEFT JOIN DIS_RATE
    ON CAR.CAR_TYPE = DIS_RATE.CAR_TYPE
    WHERE CAR.CAR_TYPE IN ('세단', 'SUV')
    AND NOT EXISTS (SELECT *
               FROM NOT_RENT
               WHERE NOT_RENT.CAR_ID = CAR.CAR_ID)) AS FINAL
WHERE FINAL.FEE >= 500000 AND FINAL.FEE < 2000000
ORDER BY FEE DESC,CAR.CAR_TYPE ASC, CAR.CAR_ID ASC

 

해법 포인트 1 

- WITH 문으로 각 테이블에서 풀이에 필요한 데이터만 추출하고자 하였다. 문제가 꽤 복잡하여, 쿼리를 읽기 어렵고 쿼리 디버깅이 힘들어서 WITH문을 사용하였다. 

 

위의 코드를 문제에 따라서 하나씩 조각내서 보자.

 

'...자동차 종류가 '세단' 또는 'SUV' 인 자동차 중 2022년 11월 1일부터 2022년 11월 30일까지 대여 가능하고...'

CAR_RENTAL_COMPANY_RENTAL_HISTORY에서 11월 1일부터 30일까지 대여가 가능한 차량을 찾는 식으로 접근하면 안된다. 하나의 차량이 기간마다 여러번 대여한 이력이 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에 있기 때문이다. 어떤 차량이 대여 가능하고 대여가 불가능한지 차량 아이디로서 구분이 가능해야 한다. 해당 기간에 대여한 차량이 '대여가 불가능한 차량들'이라는 테이블로 저장해야 한다.  

WITH NOT_RENT AS 
    (
    SELECT RENT.CAR_ID
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY AS RENT
    WHERE RENT.END_DATE >= '2022-11-01' AND RENT.START_DATE < '2022-12-01'
    )

 

해법 포인트 2

 

세단/SUV 데이터를 추출한 차량 정보 테이블과 할인율에 대한 테이블을 JOIN하여 FROM 절의 인라인 서브쿼리로 나타낸다. 

특히, 하루 비용 X 할인율 X 30일 로 나타낸 뒤, 이후에 정수로 표현하기 위해 CEILING 함수를 이용하였다. 

CEILING() : 해당 숫자보다 크거나 같은 최소 정수를 반환

    (
    SELECT CAR.CAR_ID, CAR.CAR_TYPE,
           CEILING(CAR.DAILY_FEE*DIS_RATE.DISCOUNT_RATE*30) AS FEE
    FROM CAR_RENTAL_COMPANY_CAR AS CAR
    LEFT JOIN DIS_RATE
    ON CAR.CAR_TYPE = DIS_RATE.CAR_TYPE
    WHERE CAR.CAR_TYPE IN ('세단', 'SUV')
    AND NOT EXISTS (SELECT *
               FROM NOT_RENT
               WHERE NOT_RENT.CAR_ID = CAR.CAR_ID)) AS FINAL

 

해법 포인트 3

위의 코드에서 WHERE 절에 NOT_RENT(대여가 안되는 차량 테이블 정보)와 차량 정보 테이블을 조인하여 서브 쿼리로 나타내어, 빌릴 수 있는 차량 정보만 추출한다.  

NOT EXISTS (SELECT *
               FROM NOT_RENT
               WHERE NOT_RENT.CAR_ID = CAR.CAR_ID)) AS FINAL

 

해법포인트 4

마지막으로, 연산한 FEE 열을 일정 금액 내에서 필터링 해야 하므로, 가장 밖의 쿼리문에서 WHERE 조건절을 걸어서 원하는 값을 산출한다. 

SELECT *
FROM ...
WHERE FINAL.FEE >= 500000 AND FINAL.FEE < 2000000
ORDER BY FEE DESC,CAR.CAR_TYPE ASC, CAR.CAR_ID ASC