프로그래머스 문제
https://school.programmers.co.kr/learn/courses/30/lessons/157339
풀이
https://school.programmers.co.kr/questions/73884
-- 풀이 쿼리
SELECT C.CAR_ID, C.CAR_TYPE
, ROUND((30 * C.DAILY_FEE * (1-P.DISCOUNT_RATE/100))) AS FEE
FROM CAR_RENTAL_COMPANY_CAR C
LEFT JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY H
ON C.CAR_ID = H.CAR_ID
LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN P
ON C.CAR_TYPE = P.CAR_TYPE
WHERE C.CAR_ID NOT IN
(
SELECT CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE ('2022-11-01 00:00:00' BETWEEN START_DATE AND END_DATE)
OR ('2022-11-30 23:59:59' BETWEEN START_DATE AND END_DATE)
)
AND C.CAR_TYPE IN ('세단', 'SUV')
AND P.DURATION_TYPE = '30일 이상'
GROUP BY C.CAR_ID, C.CAR_TYPE
HAVING FEE BETWEEN 500000 AND 2000000
ORDER BY FEE DESC, C.CAR_TYPE, C.CAR_ID DESC;
좀 길어 보이지만 차근차근 해석하면 어려울 것은 없다.
이 문제가 좀 까다로웠던 건 이런저런 조건이 많이 붙었기 때문.
-- 할인 가능 대여기간 : 대여 7~29일, 대여 30~89일, 대여 90일 ~
-- 차종 : 세단, SUV
-- 기간 : 2022-11-01 ~ 2022-11-30, 총 30일간 대여.
-- 대여금액 : 50만원 ~ 199만 9999원
-- 출력 : 대여 가능한 자동차ID, 자동차 종류, 대여금액(컬럼명 : FEE, 정수 형태.)
-- 정렬 : 대여금액 내림차순 차종 오름차순 차ID 내림차순
즉 22년 11월 1일 ~ 11월 30일, 총 30일간 대여금액 50만원~199만 9999원으로 세단 or SUV를 대여할건데, 대여 가능한 자동차 ID, 종류, 예상 대여금액을 정렬 기준에 맞춰서 출력하면 되는 것.
본인이 작성한 쿼리문에서 핵심이 되는 WHERE절 부분만 해석해보자.
WHERE C.CAR_ID NOT IN
(
SELECT CAR_ID
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE ('2022-11-01 00:00:00' BETWEEN START_DATE AND END_DATE)
OR ('2022-11-30 23:59:59' BETWEEN START_DATE AND END_DATE)
)
이 쿼리는 22년 11월 1일 ~ 11월 30일 사이에 대여가 가능한 자동차 ID를 출력하는 쿼리다.
우선 WHERE절 안의 쿼리를 보자.
해당 쿼리는 문제에서 요구하는 기간에 대여가 불가능한 자동차 ID를 출력한다.
START_DATE와 END_DATE 사이에 11월 1일이나 11월 30일 둘 중 하나라도 있다면, 대여가 불가능 할 것이니까.
그리고 NOT IN 구문으로, 바깥 메인 쿼리에서는 대여가 불가능한 자동차 ID를 제외한 ID를 출력하게끔 한다.
=> 대여가 가능한 자동차 ID 출력
그 외에는 문제에서 주어진 조건에 맞춰서 간단하게 쿼리를 작성하면 되기 때문에 크게 어려울 부분은 없다.
24.04.11 수정)
내가 짠 쿼리는, 11/4가 시작일이고 11/6이 마감일인 경우의 ID는 고려하지 못하는 것 아닌가? 하는 지적이 있었다.
그리고, 생각해보니 내가 틀린게 맞았다(지적해 주셔서 감사합니닷)
그래서 해당 부분도 고려할 수 있게 고쳐보았는데, 고치는 김에 전체 쿼리를 조금이나마 더 짧게끔 고쳐 보았다.
-- 수정한 쿼리
SELECT C.CAR_ID, C.CAR_TYPE
, ROUND((30 * C.DAILY_FEE * (1 - P.DISCOUNT_RATE / 100))) AS FEE
FROM CAR_RENTAL_COMPANY_CAR C
LEFT JOIN CAR_RENTAL_COMPANY_RENTAL_HISTORY H
ON C.CAR_ID = H.CAR_ID
AND (H.START_DATE <= '2022-11-30' AND H.END_DATE >= '2022-11-01')
LEFT JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN P
ON C.CAR_TYPE = P.CAR_TYPE
AND P.DURATION_TYPE = '30일 이상'
WHERE C.CAR_TYPE IN ('세단', 'SUV')
AND H.CAR_ID IS NULL
GROUP BY C.CAR_ID, C.CAR_TYPE
HAVING FEE BETWEEN 500000 AND 2000000
ORDER BY FEE DESC, C.CAR_TYPE ASC, C.CAR_ID DESC;
짧아졌나...? 개미 몸길이만큼 짧아진 것 같긴 하다.
수정된 부분을 설명해보자면,
- 서브쿼리를 쓰지 않기 위해 JOIN할 때 조건을 좀 더 추가했다.
- 첫번째 LEFT JOIN에서 START_DATE, END_DATE에 대한 조건을 걸어줌으로써 해당 조건에 해당하지 않는, 즉 START_DATE가 11/30보다 크고 END_DATE가 11/01보다 작은 경우(=11월에 대여 기록이 없는 경우)의 H.CAR_ID는 NULL값으로 나온다.
- WHERE절에서 H.CAR_ID가 NULL인 데이터로 필터링함으로써 11월에 대여기록이 없는 경우의 CAR ID를 출력할 수 있게 된다.
'코딩테스트 > SQL - 프로그래머스' 카테고리의 다른 글
SQL 고득점 kit(JOIN) - 상품을 구매한 회원 비율 구하기 (0) | 2024.03.22 |
---|---|
SQL 고득점 kit(JOIN) - 5월 식품들의 총매출 조회하기 (0) | 2024.03.20 |
SQL 고득점 kit(GROUP BY) - 노선별 평균 역 사이 거리 조회하기 (0) | 2024.03.04 |
SQL 고득점 kit(GROUP BY) - 연간 평가점수에 해당하는 평가 등급 및 성과금 조회하기 (0) | 2024.03.01 |
SQL 고득점 kit(GROUP BY) - 조건에 맞는 사원 정보 조회하기 (0) | 2024.03.01 |