0%

입양 시각 구하기(2) 해설

프로그래머스 문제 중 하나인 입양 시각 구하기(2) 풀이를 정리합니다.


해당 문제는 프로그래머스에 가입이 되어 있다면 이 페이지에서 직접 풀어볼 수 있다.

문제 정보

ANIMAL_OUTS 테이블은 동물 보호소에서 입양 보낸 동물의 정보를 담은 테이블이다. ANIMAL_OUTS 테이블 구조는 다음과 같으며, ANIMAL_ID, ANIMAL_TYPE, DATETIME, NAME, SEX_UPON_OUTCOME는 각각 동물의 아이디, 생물 종, 입양일, 이름, 성별 및 중성화 여부를 나타낸다.

NAME TYPE NULLABLE
ANIMAL_ID VARCHAR(N) FALSE
ANIMAL_TYPE VARCHAR(N) FALSE
DATETIME DATETIME FALSE
NAME VARCHAR(N) TRUE
SEX_UPON_OUTCOME VARCHAR(N) FALSE

보호소에서는 몇 시에 입양이 가장 활발하게 일어나는지 알아보려 한다. 0시부터 23시까지, 각 시간대별로 입양이 몇 건이나 발생했는지 조회하는 SQL문을 작성해라. 이때 결과는 시간대 순으로 정렬해야 한다.

정답 코드

먼저 정답은 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
SELECT
T.HOUR,
IFNULL(D.COUNTS,
0) AS COUNT
FROM
(SELECT
@N:=@N 1 AS HOUR
FROM
ANIMAL_OUTS,
(SELECT
@N:=-1
FROM
DUAL) NN LIMIT 24) AS T
LEFT JOIN
(
SELECT
HOUR(DATETIME) AS HOUR,
COUNT(ANIMAL_ID) AS COUNTS
FROM
ANIMAL_OUTS
GROUP BY
HOUR
ORDER BY
HOUR
) AS D
ON T.HOUR = D.HOUR

문제 해설

일단 문제를 크게 3개로 나눠서 생각했다.

  • 시간대 필드 생성 쿼리
  • 입양 건수를 세는 쿼리
  • 최종 도출 쿼리

각각의 쿼리를 분석해보자.

시간대 필드 생성 쿼리

위 문제는 데이터가 없는 시간대도 쿼리 상에서 결과를 같이 도출해야 한다. 예를 들어 1시에 입양 건수가 없어도 이를 레코드로 가져와야 한다. 따라서 0 ~ 23을 레코드로 가지는 필드를 생성한다. 해당 쿼리는 아래와 같다.

1
2
3
4
5
6
7
8
SELECT
@N:=@N+1 AS HOUR
FROM
ANIMAL_OUTS,
(SELECT
@N:=-1
FROM
DUAL) NN LIMIT 24)

DUAL은 함수에 따른 결과값을 도출하고 싶을 때 사용하는 임시 더미 테이블이다. 변수 N-1을 할당하여 더미 테이블을 생성한다. 생성된 더미 테이블은 아래와 같다.

@N:=-1
-1

위 더미와 ANIMAL_OUTS을 조인한 결합 테이블에서 1씩 더해지는 변수 N을 조회하여 가져온다. LIMIT 으로 24로 제한을 두어 0부터 23까지 레코드가 도출되도록 한다.
위 쿼리의 결과는 아래와 같다.

HOUR
0
1
22
23

입양 건수를 세는 쿼리

이 쿼리는 ANIMAL_ID의 개수를 확인하여 각 시간별로의 입양 건수를 가져온다. 해당 쿼리는 아래와 같다.

1
2
3
4
5
6
7
8
9
SELECT
HOUR(DATETIME) AS HOUR,
COUNT(ANIMAL_ID) AS COUNTS
FROM
ANIMAL_OUTS
GROUP BY
HOUR
ORDER BY
HOUR

ANIMAL_OUTS라는 테이블에는 DATETIME 타입의 날짜 및 시간 필드가 있다. 해당 필드에서 HOUR()을 사용하여 시간만을 도출하고 이를 GROUP BY 대상으로 사용하여 각 시간대별로 입양 건수가 합쳐져서 반환될 수 있도록 한다. 다음으로 ORDER BY하여 시간대 별로 정렬한다. 위 쿼리의 결과는 아래와 같다.

HOUR COUNTS
7 3
8 1
18 16
19 2

위 결과에서 입양 건수가 있는 시간대만 반환되는 것을 볼 수 있다.

최종 도출 쿼리

이제 위 두개의 쿼리를 하나로 합쳐서 가져오면 된다. 먼저 쿼리의 구조를 살펴보자.

1
2
3
4
5
6
7
8
9
SELECT
T.HOUR,
IFNULL(D.COUNTS,
0) AS COUNT
FROM
(시간대 쿼리) AS T
LEFT JOIN
(입양건수 쿼리) AS D
ON T.HOUR = D.HOUR

위 쿼리는 두 테이블의 HOUR 필드를 기준으로 LEFT JOIN하여 시간 테이블인 T의 HOUR 필드와 입양건수 테이블인 D의 COUNT 필드의 값을 가져온다. 또한 T의 HOUR 필드 값이 D에 없는 경우 발생하는 NULL은 IFNULL()을 통해 0으로 변경한다.
위 쿼리의 결과는 아래와 같으며, 이는 정답 예시와 동일하다.

HOUR COUNT
0 0
1 0
22 0
23 0