본문 바로가기
Mysql

프로그래머스 SQL 고득점 Kit (GROUP BY) 입양 시각 구하기(2)

by 열정적인 이찬형 2021. 11. 8.

문제 링크

프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr

문제 설명

ANIMAL_INS 테이블은 동물 보호소에 들어온 동물의 정보를 담은 테이블입니다. 

ANIMAL_INS 테이블 구조는 다음과 같으며, ANIMAL_ID, ANIMAL_TYPE, DATETIME, INTAKE_CONDITION, NAME,SEX_UPON_INTAKE는 각각 동물의 아이디, 생물 종, 보호 시작일, 보호 시작 시 상태, 이름, 성별 및 중성화 여부를 나타냅니다.

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


테이블


문제 결과

따라서 SQL문을 실행하면 다음과 같이 나와야 합니다.


접근 방법

※ 처음 접근하였을 때

  • LEFT OUTER JOIN을 사용하여 시간이 없는 경우를 NULL을 추가한다.
  • COUNT는 NULL값을 계산하지 않기 때문에 IFNULL()을 이용해서 NULL값에 0을 추가하고 COUNT를 진행하도록  접근하였습니다.
  • 코드를 수정하면서 진행하였지만 계속 오답이 나와서 문제점을 찾기 시작하였습니다.
  • 문제점은 LEFT OUTER JOIN을 사용해서 DATETIME에 HOUR 형태가  0~23시까지 모든 값이 존재하지 않아서 HOUR값이 0~23까지 생성되지 않는다는 것을 발견하였습니다. 그래서 다른 방식을 검색해서 찾아보기 시작하였습니다.

※ 정보를 검색하여 찾아본 이후에 접근방법

  • 가상테이블 명령어 WITH에 재귀문 RECURSIVE을 사용하여 0~23시를 가진 가상테이블을 만든다.
with recursive TIMETABLE as(
	select 0 as HOUR				#처음 기본값, 별칭 HOUR 
	union all						 
    select HOUR+1 from TIMETABLE where HOUR<23	#재귀 조건 
    )

Select * From TIMETABLE 문을 실행하였을 경우 결과문

저는 JAVA에 FOR문과 비슷한 형태로 이해하였습니다.

List<Integer> list = new ArrayList<>();		//값을 담을 list 
for(int i=0;i<=23;i++){				//for문을 통한 재귀 	
list.add(i)					//값을 list에 넣음     
}
  • SQL 문의 조회 명령어 SELECT문에서 HOUR과 시간과 동일한 ANIMAL_ID에 개수를 출력해야 한다.

※ 개수를 출력할 때에 ANIMAL_ID말고도 ANIMAL_TYPE,DATETIME 등으로 작성해도 됩니다. 하지만 NAME은 사용하면 오답입니다. 왜냐하면 NAMENULLABLE이 가능한 특징을 가지고 있어서 만약 NULL값이 있으면 COUNTNULL값을 무시하고 넘어가기 때문에 올바른 정답이 출력되지 않습니다.

  • COUNT문을 사용하였으며 결과는 COUNT로 출력되어 AS문도 사용하였습니다.
  • TIMETABLE 기준으로 OUTER JOIN을 하기 위해 LEFT OUTER JOIN을 진행하였습니다.
  • GROUP BY 결과값에 조건인 ON을 사용하여 TIMETALBE에 HOUR과 ANIMAL_INS에 DATETIME에 HOUR값을 동일한 것들만 결과로 출력하도록 하였습니다.
  • TIMETABLE에 HOUR 속성을 묶기 때문에 GROUP BY HOUR을 사용하였습니다.
  • 마지막으로 결과를 시간순으로 조회하라는 조건이 있으므로 HOUR을 오름차순으로 정렬(ORDER BY) 하였습니다.

결과 코드

with recursive TIMETABLE as(
	select 0 as HOUR 
    union all 
    select HOUR+1 from TIMETABLE where HOUR<23
    ) 
    select HOUR,COUNT(DATETIME) AS COUNT from TIMETABLE LEFT OUTER JOIN ANIMAL_OUTS 
    ON HOUR = date_format(DATETIME,"%H")		#hour(DATETIME)을 사용해도 상관없다. 
    GROUP BY HOUR 
    ORDER BY HOUR;

공부 내역

재귀 가상 테이블(WITH RECURSIVE)

WITH RECURSIVE 테이블이름 AS( 	
	SELECT 초기값 AS 별칭 	
    UNION ALL     
    SELECT 별칭계산식 FROM 테이블이름 WHERE 조건    
    )

나중에 데이터베이스 관련 기능을 설계할 때 매우 유용할 것 같다.

댓글