문제 공유: https://school.programmers.co.kr/learn/courses/30/lessons/157339
프로그래머스
SW개발자를 위한 평가, 교육, 채용까지 Total Solution을 제공하는 개발자 성장을 위한 베이스캠프
programmers.co.kr
[문제설명]
다음은 어느 자동차 대여 회사에서 대여 중인 자동차들의 정보를 담은 CAR_RENTAL_COMPANY_CAR 테이블과 자동차 대여 기록 정보를 담은 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블과 자동차 종류 별 대여 기간 종류 별 할인 정책 정보를 담은 CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블 입니다.
CAR_RENTAL_COMPANY_CAR 테이블은 아래와 같은 구조로 되어있으, CAR_ID, CAR_TYPE, DAILY_FEE, OPTIONS 는 각각 자동차 ID, 자동차 종류, 일일 대여 요금(원), 자동차 옵션 리스트를 나타냅니다.
Column name | Type | Nullable |
CAR_ID | INTEGER | FALSE |
CAR_TYPE | VARCHAR(255) | FALSE |
DAILY_FEE | INTEGER | FALSE |
OPTIONS | VARCHAR(255) | FALSE |
자동차 종류는 '세단', 'SUV', '승합차', '트럭', '리무진' 이 있습니다. 자동차 옵션 리스트는 콤마(',')로 구분된 키워드 리스트(예: ''열선시트,스마트키,주차감지센서'')로 되어있으며, 키워드 종류는 '주차감지센서', '스마트키', '네비게이션', '통풍시트', '열선시트', '후방카메라', '가죽시트' 가 있습니다.
CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블은 아래와 같은 구조로 되어있으, HISTORY_ID, CAR_ID, START_DATE, END_DATE 는 각각 자동차 대여 기록 ID, 자동차 ID, 대여 시작일, 대여 종료일을 나타냅니다.
Column name | Type | Nullable |
HISTORY_ID | INTEGER | FALSE |
CAR_ID | INTEGER | FALSE |
START_DATE | DATE | FALSE |
END_DATE | DATE | FALSE |
CAR_RENTAL_COMPANY_DISCOUNT_PLAN 테이블은 아래와 같은 구조로 되어있으며, PLAN_ID, CAR_TYPE, DURATION_TYPE, DISCOUNT_RATE 는 각각 요금 할인 정책 ID, 자동차 종류, 대여 기간 종류, 할인율(%)을 나타냅니다.
Column name | Type | Nullable |
PLAN_ID | INTEGER | FALSE |
CAR_TYPE | VARCHAR(255) | FALSE |
DURATION_TYPE | VARCHAR(255) | FALSE |
DISCOUNT_RATE | INTEGER | FALSE |
할인율이 적용되는 대여 기간 종류로는 '7일 이상' (대여 기간이 7일 이상 30일 미만인 경우), '30일 이상' (대여 기간이 30일 이상 90일 미만인 경우), '90일 이상' (대여 기간이 90일 이상인 경우) 이 있습니다. 대여 기간이 7일 미만인 경우 할인정책이 없습니다.
[문제]
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를 기준으로 내림차순 정렬해주세요.
풀이 설명
MySQL 보다는 TIBERO 때문에 나한테 친숙한 ORACLE 쿼리를 사용했다.
문제에서 설명한 3개 테이블을 전부다 JOIN을 해야되는줄 알고 JOIN을 하였으나, 레벨 4 답게 위기가 한번 있었다.
해당 위기를 제외하고는 대여 금액이 FEE 의 조건이 50만원 이상 200만원 이하라서 SELECT 로 한번 더 감싸서 조건을 추가하고 문제에 맞게 ORDER BY 추가해서 통과.
함정)
대여가능한 일정이 11/1~11/30 까지 가능한 차량만 뽑아야된다는 것이다.
해당 조건 관련해서는 CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에서 11/1~11/30에 빌린 데이터가 없는 것을 뽑아야 했었다.
지금 생각해보면 간단한 풀이로 설명이 가능하다. (저때는 한창 생각했었다.)
결론부터 말하면 END_DATE 가 22년 11월 1일 이상인 것만 빼고 데이터를 가져오면 된다.
그래서 제외하기 위해 서브쿼리로 하여 NOT IN을 사용.
이상인 데이터들은 지금 현재 누군가가 빌린 자동차라는 의미이다.
다행히도 HISTORY 테이블이라서 누가 미리 예약한 데이터는 없었다.
(예를 들어 누가 12월 1일부터 미리 예약했으면 그건 빌릴수 있지만, 해당 조건에 걸려서 못빌리는 것으로 결과가 나온다.)
[ 제출한 정답 쿼리 ]
SELECT T.CAR_ID , T.CAR_TYPE , T.FEE
FROM (
-- Output : 자동차 ID, 자동차 종류, 대여 금액(컬럼명 FEE)
SELECT A.CAR_ID , A.CAR_TYPE, (A.DAILY_FEE * ((1-C.DISCOUNT_RATE/100)) * 30) AS FEE
FROM CAR_RENTAL_COMPANY_CAR A
JOIN CAR_RENTAL_COMPANY_DISCOUNT_PLAN C
ON A.CAR_TYPE = C.CAR_TYPE
WHERE A.CAR_TYPE IN ('SUV','세단') -- 1st 조건
AND C.DURATION_TYPE = '30일 이상' -- 3rd 조건
AND A.CAR_ID NOT IN (SELECT B.CAR_ID -- 2nd 조건
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY B
WHERE B.END_DATE >= TO_DATE('2022-11-01', 'YYYY-MM-DD')
) T
WHERE T.FEE BETWEEN 500000 AND 2000000 -- 4th 조건
ORDER BY T.FEE DESC , T.CAR_TYPE ASC , T.CAR_ID DESC
;
옛날에는 무슨 쿼리를 만들면 결과만 같으면 되는거 아닌가? 라는 생각이었지만, 프로젝트 경험을 겪은 후에는 느끼는 것은 옛날에는 정말 아무것도 몰랐구나 라는 생각이 든다. 데이터량이 적으면 큰 문제가 없지만, 데이터량이 많아질수록 쿼리 튜닝에 대한 필요성이 크게 느껴진다. 해당 테이블의 인덱스가 뭐가 있는지.. 어떤 힌트를 줘서 옵션을 줘야 효과가 좋은지.. 등등 고려해서 쿼리를 만들어야지 나중에 고생을 안한다.
'Coding_TEST' 카테고리의 다른 글
[Baekjoon 1032] 명령 프롬프트 (python) (0) | 2021.06.13 |
---|---|
[Baekjoon 2839] 설탕 배달 (python) (0) | 2021.06.12 |
[Baekjoon 1157] 단어 공부 (python) (0) | 2021.06.11 |
[Baekjoon 2750] 수 정렬하기 (python - 버블정렬) (0) | 2021.06.10 |
[Baekjoon 1546] 평균 (python) (0) | 2021.06.09 |