SQL 고득점 Kit - 9.3

김동현·2024년 9월 3일

SQL 고득점 Kit

목록 보기
46/56

GROUP BY - 자동차 대여 기록에서 대여중 / 대여 가능 여부 구분하기

문제

CAR_RENTAL_COMPANY_RENTAL_HISTORY 테이블에서 2022년 10월 16일에 대여 중인 자동차인 경우 '대여중' 이라고 표시하고, 대여 중이지 않은 자동차인 경우 '대여 가능'을 표시하는 컬럼(컬럼명: AVAILABILITY)을 추가하여 자동차 ID와 AVAILABILITY 리스트를 출력하는 SQL문을 작성해주세요. 이때 반납 날짜가 2022년 10월 16일인 경우에도 '대여중'으로 표시해주시고 결과는 자동차 ID를 기준으로 내림차순 정렬해주세요.

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

1차 풀이

-- 대여 가능, 대여중 둘 다 있을 때 대여중이 떠야 됨
WITH car AS(
    SELECT
        CAR_ID, 
        CASE
            WHEN END_DATE >= '2022-10-16' THEN '대여중'
            ELSE '대여 가능'
        END 'AVAILABILITY'
    FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY
    GROUP BY CAR_ID, AVAILABILITY
    ORDER BY CAR_ID, AVAILABILITY 
)
-- 2가지가 존재하면 중복 ID가 존재한다. 따라서 그 중복 ID는 다 대여중으로 변환
SELECT *, IF(COUNT(*) = 2, '대여중','대여 가능')  cnt
FROM car
GROUP BY CAR_ID

리뷰

  • 대여중, 대여 가능 두 가지가 모두 나오는 쿼리이기 때문에 날짜를 어떻게 하나로 판단하고 접근할 수 있을까가 해결해야 되는 포인트였다.
  • 위 쿼리로 하면 대여중, 대여 가능이 뒤바뀌고, 원하는 결과가 나오지 않는다.
  • 해당 부분을 해결하기 위해서 2차 풀이 형태로 생각을 바꿔서 풀이를 진행했다.

2차 풀이

SELECT 
    CAR_ID,
    CASE
        WHEN MAX(END_DATE) >= '2022-10-16' THEN '대여중' -- 반납 날짜가 2022.10.16 기준으로 대여중
        ELSE '대여 가능' -- 아니라면 대여 가능
    END 'AVAILABILITY'
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
GROUP BY CAR_ID -- CAR_ID로 그룹화를 해서 날짜의 최소, 최대 기간을 한 번에 확인
ORDER BY CAR_ID DESC

리뷰

  • 날짜를 한 번에 확인할 수 있는 것이 무엇일까 고민을 통해 MAX를 사용한다면 ID별 반납일의 최대를 알 수 있다고 판단했고, 그것을 활용하면 원하는 결과가 나올 것이라 생각했다.
  • 하지만 반납 날짜만 보고 대여 여부를 판단한 것이 잘못되었다. (접근은 좋았다고 생각함 ㅋㅋㅋㅋㅋ) 문제에서 요구하는 것을 제대로 인지하지 못 한 것이 패착이다. 날짜가 한 사이클로 존재할 텐데 그 사이클 안에서 특정 날짜가 존재하는지를 판단해야 하는데 최대로만 판단하니 특정 날짜에 대여 여부를 판단할 수 없다.
  • 그것을 할 수 있는 것이 BETWEEN 함수!!

3차 풀이

SELECT 
    CAR_ID,
    CASE
        ## ID별 기간 중 특정 날짜가 있으면 1 없으면 0에서 MAX로 인해 동일한 ID 결과 중 최고 값으로만 값이 반환
        WHEN MAX('2022-10-16' BETWEEN START_DATE AND END_DATE) THEN '대여중'
        ELSE '대여 가능' -- 아니라면 대여 가능
    END 'AVAILABILITY'
FROM CAR_RENTAL_COMPANY_RENTAL_HISTORY 
GROUP BY CAR_ID -- CAR_ID로 그룹화를 해서 날짜 기간을 한 번에 확인
ORDER BY CAR_ID DESC

리뷰

  • CASE문은 참, 거짓으로도 판별을 할 수 있는 IF문과 같은 매커니즘이기 때문에 BETWEEN에서 반환하는 0, 1의 값 중 MAX로 인해서 1이 존재하는 사이클를 추출할 것이다.
  • 그로 인해 1이 존재하는 ID는 대여중, 1이 없는 ID는 0으로 ELSE문을 통해 대여 가능을 반환할 것이다.
  • (근데 저렇게 쿼리를 짤 수 있다는 것을 신기했다... 아직 머리가 저렇게 안 돌아가는 듯)

SELECT - 대장균들의 자식의 수 구하기

문제

대장균 개체의 ID(ID)와 자식의 수(CHILD_COUNT)를 출력하는 SQL 문을 작성해주세요. 자식이 없다면 자식의 수는 0으로 출력해주세요. 이때 결과는 개체의 ID 에 대해 오름차순 정렬해주세요.

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

1차 풀이

WITH id AS(
    SELECT 
        IFNULL(PARENT_ID, 0) PARENT, -- 그룹화 후 NULL은 출력되지 않음
        COUNT(PARENT_ID) cnt
    FROM ECOLI_DATA 
    GROUP BY PARENT_ID -- 그룹화를 해야 COUNT를 할 수 있다. 
)

SELECT 
    ID,
    IFNULL(cnt, 0) CHILD_COUNT -- 자식이 없는 NULL은 0으로 변환
FROM id i
RIGHT JOIN ECOLI_DATA e
ON i.PARENT = e.ID -- ID와 PARENT를 조인해서 자식의 수를 맵핑한다.
ORDER BY ID

2차 풀이

SELECT 
    e.ID,
    COUNT(i.PARENT_ID) CHILD_COUNT
FROM ECOLI_DATA i
RIGHT JOIN ECOLI_DATA e
ON i.PARENT_ID = e.ID -- ID와 PARENT를 조인해서 자식의 수를 맵핑한다.
GROUP BY e.ID
ORDER BY e.ID

리뷰

  • 1차 풀이처럼 CTE를 사용하여 쿼리를 작성했다. 그렇기 때문에 cnt 값도 NULL을 변환해야 하고 쿼리도 길다.
  • 하지만 정답이기에 넘어가려고 하다가 너무 길기도 하고 한 번에 풀 수 있는 방법이 없나 생각하다가 (난 왜 셀프 조인, between 같은 함수나 풀이가 생각이 안 날까?...) 다른 사람의 셀프 조인으로 풀이를 보고 너무 쉽게 접근 및 간단한 쿼리를 통해 다시 수정을 했다.
  • 그 이유는 내가 문제를 빠르게 풀려고 어려운 방법으로만 생각을 해서 아닐까? 생각해본다. 좀 더 깊게 문제를 다양한 관점으로 봐야하는데 아직 한 문제 풀이로만 생각했기 때문이라고 느낀다.

GitHub

자동차 대여 기록에서 대여중 / 대여 가능 여부 구분하기
https://github.com/lasentia/SQL_Study/tree/main/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/3/157340.%E2%80%85%EC%9E%90%EB%8F%99%EC%B0%A8%E2%80%85%EB%8C%80%EC%97%AC%E2%80%85%EA%B8%B0%EB%A1%9D%EC%97%90%EC%84%9C%E2%80%85%EB%8C%80%EC%97%AC%EC%A4%91%E2%80%85%EF%BC%8F%E2%80%85%EB%8C%80%EC%97%AC%E2%80%85%EA%B0%80%EB%8A%A5%E2%80%85%EC%97%AC%EB%B6%80%E2%80%85%EA%B5%AC%EB%B6%84%ED%95%98%EA%B8%B0

대장균들의 자식의 수 구하기
https://github.com/lasentia/SQL_Study/tree/main/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4/3/299305.%E2%80%85%EB%8C%80%EC%9E%A5%EA%B7%A0%EB%93%A4%EC%9D%98%E2%80%85%EC%9E%90%EC%8B%9D%EC%9D%98%E2%80%85%EC%88%98%E2%80%85%EA%B5%AC%ED%95%98%EA%B8%B0

profile
'The best way to get started is to quit talking and begin doing.'

0개의 댓글