MySQL 프로그래머스 | 멸종 위기의 대장균 찾기 (재귀쿼리로 자식 없는 개체수 구하기)

728x90

 

문제

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

 

프로그래머스

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

programmers.co.kr

  • 각 세대별, 자식이 없는 개체의 수(COUNT)와 세대(GENERATION)를 출력하는 SQL문을 작성
  • 결과는 세대 기준 오름차순 정렬
  • 모든 세대에는 자식이 없는 개체가 적어도 1개체는 존재함

 

테이블

ECOLI_DATA
  • 자식이 없는 개체 : 빨간 박스1, 3, 5, 7, 8
    • 자식이 없으면 PARENT_ID에 자신의 ID가 없음

 

풀이과정

# 세대구분 재귀쿼리 만들기

  • 재귀쿼리 첫 번째 테이블은 PARENT_ID가 NULL인 1세대의 경우, GENERATION을 1로 명명
  • 재귀쿼리 두 번째 테이블부터는 자신의 PARENT_ID가 이전 재귀쿼리 결과 테이블의 ID와 같을 때
    GENERATION이 +1씩 되도록 함 
1
2
3
4
5
6
7
8
9
10
11
12
WITH RECURSIVE GE AS (SELECT ID, 
                             1 AS GENERATION
                      FROM   ECOLI_DATA
                      WHERE  PARENT_ID IS NULL
                      
                      UNION ALL
                      
                      SELECT A.ID, 
                             B.GENERATION + 1 AS GENERATION
                      FROM   ECOLI_DATA A, GE B
                      WHERE  A.PARENT_ID = B.ID
                     )
cs

 

 

# 원래 테이블과 세대구분 테이블 조인

  • 원래 테이블의 ID가 세대 구분 테이블의 ID와 같을 때 조인되게 함 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
WITH RECURSIVE GE AS (SELECT ID, 
                             1 AS GENERATION
                      FROM   ECOLI_DATA
                      WHERE  PARENT_ID IS NULL
                      
                      UNION ALL
                      
                      SELECT A.ID, 
                             B.GENERATION + 1 AS GENERATION
                      FROM   ECOLI_DATA A, GE B
                      WHERE  A.PARENT_ID = B.ID
                     )
                     
SELECT *
FROM ECOLI_DATA A, GE B
WHERE A.ID = B.ID
cs

 

 

# 자식 개체가 없는 ID 필터링하기

  • 자식 개체가 없으면, 자신의 ID가 PARENT_ID에 속하지 않아야 함
  • (주의) IN 또는 NOT IN 함수를 사용할 때는 안에 NULL 데이터가 있으면 안됨! (NULL이 있으면 결과가 안 나옴)
    전체 PARENT_ID를 조회하면 NULL (1세대) 데이터가 존재하기 때문에 서브쿼리 내에 WHERE절을 사용해 
    PARENT ID IS NOT NULL 조건을 추가함
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 WITH RECURSIVE GE AS (SELECT ID, 
                             1 AS GENERATION
                      FROM   ECOLI_DATA
                      WHERE  PARENT_ID IS NULL
                      
                      UNION ALL
                      
                      SELECT A.ID, 
                             B.GENERATION + 1 AS GENERATION
                      FROM   ECOLI_DATA A, GE B
                      WHERE  A.PARENT_ID = B.ID
                     )
                     
SELECT *
FROM ECOLI_DATA A, GE B
WHERE A.ID = B.ID
AND A.ID NOT IN(SELECT DISTINCT PARENT_ID FROM ECOLI_DATA WHERE PARENT_ID IS NOT NULL)
cs

 

 

# 정답

  • 각 세대 별자식 개체가 없는 ID들COUNT값을 구해야 하기 때문에 
    GENERATION으로 GROUP BY 해준 뒤 ID를 카운트 해줌
  • 세대 기준 오름차순 정렬까지 해주면 끝!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
WITH RECURSIVE GE AS (SELECT ID, 
                             1 AS GENERATION
                      FROM   ECOLI_DATA
                      WHERE  PARENT_ID IS NULL
                      
                      UNION ALL
                      
                      SELECT A.ID, 
                             B.GENERATION + 1 AS GENERATION
                      FROM   ECOLI_DATA A, GE B
                      WHERE  A.PARENT_ID = B.ID
                     )
                     
SELECT COUNT(A.ID) COUNT, GENERATION
FROM ECOLI_DATA A, GE B
WHERE A.ID = B.ID
AND A.ID NOT IN(SELECT DISTINCT PARENT_ID FROM ECOLI_DATA WHERE PARENT_ID IS NOT NULL)
GROUP BY GENERATION
ORDER BY GENERATION
cs

 

 

 

 

728x90

댓글