본문 바로가기

데이터 베이스/Programmers

[프로그래머스 SQL 고득점 Kit] 대여 횟수가 많은 자동차들의 월별 대여 횟수 구하기

데이터 그룹핑 문제

https://school.programmers.co.kr/learn/courses/30/lessons/151139

 

 


[문제 설명]

 

8월~10월 사이의 총 대여 횟수가 5회 이상인 차들에 대해 월별로 몇 번 대여 됐는지를 알아내는 문제입니다.

대여 시작일(AS MONTH), 자동차 ID, 월별 대여 횟수(AS RECORDS)를 출력하면 됩니다.

대여가 한 번도 되지 않은 월은 출력하지 않고, 월을 기준으로 오름차순, 그 후에는 자동차 ID를 기준으로 내림차순 정렬해야 한다는 조건이 있습니다.

 

차근차근 보겠습니다.

 


출력이 대여 시작일, 자동차 ID, 월별 대여 횟수로 지정되어 있으므로

 

  • 대여 시작일: date타입인 START_DATE를 월만 잘라서 출력.
  • 자동차 ID: 그냥 CAR_ID 출력.
  • 자동차에 대한 월별 대여 횟수: 자동차 ID와 대여 시작일에 대해 그룹핑하고 COUNT(*) 결과를 출력.

아직까지는 간단합니다.

 

SELECT EXTRACT(MONTH FROM START_DATE) MONTH, CAR_ID, COUNT(*) RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
GROUP BY EXTRACT(MONTH FROM START_DATE), CAR_ID;

 

현재까지의 진행상태를 코드로 나타내면 위와 같습니다.

 


출력 틀은 다 짰으니 세부적인 부분을 처리하겠습니다.

 

  • 8월~10월 사이: 8월과 10월이 아닌 값은 필요가 없으므로 WHERE(성능 면에서 유리)이나 HAVING에서 제거.
  • 대여가 한 번도 되지 않은 월은 제거해야 하므로 그룹핑 후의 COUNT(*)가 0인 행을 HAVING에서 제거.
  • 정렬하는 기준에 대해 ORDER BY.

차근차근 보니 아직까지도 무난합니다.

 

SELECT EXTRACT(MONTH FROM START_DATE) MONTH, CAR_ID, COUNT(*) RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE 8 <= EXTRACT(MONTH FROM START_DATE) AND EXTRACT(MONTH FROM START_DATE) < 11
GROUP BY EXTRACT(MONTH FROM START_DATE), CAR_ID
HAVING COUNT(*) <> 0
ORDER BY MONTH, CAR_ID DESC;

 

현재까지의 진행상태를 코드로 나타내면 위와 같습니다.

 


마지막 조건 하나만 남은 상황입니다.

8월에서 10월 사이의 대여 횟수가 5대 이상이어야 합니다.

 

 

8월에서 10월 사이의 총 대여 횟수를 구하는 방법을 생각해 봅시다.

MONTH의 범위를 8월과 10월로 제한하고 CAR_ID로 그룹핑한 후에, COUNT(*)해주면 총횟수를 구할 수 있습니다.

그런데 우리는 이미 출력문을 짜는 과정에서 MONTH와 CAR_ID로 그룹핑을 하였기 때문에 위와 같은 방법은 불가능합니다.

 

그래서 서브쿼리를 사용합니다.

 

서브쿼리 내에서 아래 과정과 같이 처리하고 처리된 CAR_ID들을 메인쿼리의 WHERE(성능 면에서 유리) 혹은 HAVING에서 검사하면 됩니다.

 

  • CAR_ID로 그룹핑.
  • 8월과 10월 사이의 횟수가 필요하므로 이외의 경우는 WHERE(성능 면에서 유리)이나 HAVING에서 제거.
  • 그룹핑 후의 COUNT(*)가 5 이상인 행만 필요하므로 HAVING에서 제거.

이렇게 하고 나면 8월에서 10월 사이에 총 대여 횟수가 5이상인 모든 차량(차량 그룹핑)에 대해 → 서브 쿼리

월별, 차량별(월, 차량 그룹핑) 대여 횟수를 출력할 수 있습니다. → 메인 쿼리

 


[소스 코드] / ORACLE SQL

 

SELECT EXTRACT(MONTH FROM START_DATE) MONTH, CAR_ID, COUNT(*) RECORDS
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
WHERE CAR_ID IN (
    SELECT CAR_ID
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
    WHERE EXTRACT(MONTH FROM START_DATE) IN (8, 9, 10) 
    GROUP BY CAR_ID
    HAVING COUNT(*) > 4
) AND 8 <= EXTRACT(MONTH FROM START_DATE) AND EXTRACT(MONTH FROM START_DATE) < 11
GROUP BY EXTRACT(MONTH FROM START_DATE), CAR_ID
HAVING COUNT(*) <> 0
ORDER BY MONTH, CAR_ID DESC;