데이터 그룹핑 문제
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;
'데이터 베이스 > Programmers' 카테고리의 다른 글
[프로그래머스 SQL 고득점 Kit] 중복 제거하기 (0) | 2023.02.08 |
---|