[프로그래머스/MySQL/SELECT/LV.4] 특정 세대의 대장균 찾기

sammy·2026년 3월 4일

SQL 문제풀이

목록 보기
87/87

🧩 문제

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


📌 문제 설명

대장균은 분화하며, 분화를 시작한 개체를 부모, 분화되어 나온 개체를 자식이라고 한다.

ECOLI_DATA 테이블에는 대장균 개체의 ID와 부모 ID 등이 저장되어 있고, 최초 개체(루트)는 PARENT_IDNULL이다.

📂 테이블 구조

Column nameTypeNullable
IDINTEGERFALSE
PARENT_IDINTEGERTRUE
SIZE_OF_COLONYINTEGERFALSE
DIFFERENTIATION_DATEDATEFALSE
GENOTYPEINTEGERFALSE

🎯 문제 목표

3세대 대장균의 ID를 출력하는 SQL을 작성한다.

  • 출력 컬럼: ID
  • 정렬: ID 오름차순

🧠 문제 접근 (Approach)

이 문제는 PARENT_ID → ID 관계로 트리(계보)가 만들어지는 구조라서, “세대”는 루트에서부터 내려온 깊이(depth) 로 볼 수 있습니다.

3세대만 구하면 되므로, 재귀를 쓰지 않고 SELF JOIN을 2번 해서

  • 1세대(루트) → 2세대 → 3세대

를 만들면 됩니다.

👉 핵심 아이디어 한 줄 요약

PARENT_ID IS NULL인 루트에서 시작해 self join 2번으로 3세대만 뽑습니다.


✅ 내 정답 (SELF JOIN)

SELECT g3.ID
FROM ECOLI_DATA g1
JOIN ECOLI_DATA g2 ON g2.PARENT_ID = g1.ID
JOIN ECOLI_DATA g3 ON g3.PARENT_ID = g2.ID
WHERE g1.PARENT_ID IS NULL
ORDER BY g3.ID;

왜 이게 3세대인가?

  • g1: 1세대(부모가 없는 루트, PARENT_ID IS NULL)
  • g2: 2세대(1세대의 자식)
  • g3: 3세대(2세대의 자식)

🧷 짚고가기: SELF JOIN vs 재귀 CTE

1) SELF JOIN (깊이가 고정일 때)

세대가 “3세대”처럼 고정된 값이라면 SELF JOIN이 제일 직관적입니다.

  • 장점: 간단하고 빠르게 읽힘
  • 단점: 4세대, 5세대…로 바뀌면 JOIN을 계속 늘려야 함

예시: 2세대 찾기

SELECT c.ID
FROM ECOLI_DATA p
JOIN ECOLI_DATA c ON c.PARENT_ID = p.ID
WHERE p.PARENT_ID IS NULL
ORDER BY c.ID;

예시: 3세대 찾기 (이번 문제)

SELECT g3.ID
FROM ECOLI_DATA g1
JOIN ECOLI_DATA g2 ON g2.PARENT_ID = g1.ID
JOIN ECOLI_DATA g3 ON g3.PARENT_ID = g2.ID
WHERE g1.PARENT_ID IS NULL
ORDER BY g3.ID;

2) 재귀 CTE (깊이가 변할 때)

“특정 N세대”처럼 세대(depth)가 바뀔 수 있는 문제라면 재귀 CTE가 유리합니다.

  • 장점: N만 바꾸면 재사용 가능
  • 단점: SQL 문법이 처음엔 조금 낯설 수 있음

예시: 모든 개체의 세대(gen) 계산

WITH RECURSIVE gens AS (
  -- 1세대(루트)
  SELECT ID, PARENT_ID, 1 AS gen
  FROM ECOLI_DATA
  WHERE PARENT_ID IS NULL

  UNION ALL

  -- 부모(gen) + 1 => 자식 gen
  SELECT e.ID, e.PARENT_ID, g.gen + 1
  FROM ECOLI_DATA e
  JOIN gens g ON e.PARENT_ID = g.ID
)
SELECT *
FROM gens;

예시: 3세대만 출력

WITH RECURSIVE gens AS (
  SELECT ID, PARENT_ID, 1 AS gen
  FROM ECOLI_DATA
  WHERE PARENT_ID IS NULL

  UNION ALL

  SELECT e.ID, e.PARENT_ID, g.gen + 1
  FROM ECOLI_DATA e
  JOIN gens g ON e.PARENT_ID = g.ID
)
SELECT ID
FROM gens
WHERE gen = 3
ORDER BY ID;

💡 정리

  • 세대가 고정(예: 3세대)이라면: SELF JOIN이 가장 간단
  • 세대가 가변(예: N세대)이라면: WITH RECURSIVE로 depth를 일반화
profile
누군가에게 도움을 주기 위한 개발자로 성장하고 싶습니다.

0개의 댓글