재귀 함수 정복하기

profile image 스이연 2025. 2. 9. 23:47

프로그래머스 SQL 문제를 풀던 중 재귀함수를 이용해야하는 문제가 생겼다.평상시에도 재귀를 어려워했어서 그런지 SQL에서도 재귀를 사용한다는 것에 겁이났지만...😭 극복하기 위해 공부한 내용을 적어보려한다!

 

WITH RECURSIVE 문

RECURSIVE 쿼리란

데이터베이스에서 재귀적으로 데이터를 조회하거나 처리하는데 사용 되는 쿼리다.

메모리 상에 가상의 테이블을 저장해서 실제로 테이블을 생성하거나 데이터 삽입을 하지 않아도 가상 테이블을 생성할 수 있다.

활용

  • 계층적 데이터 조회
    • 조직도, 카테고리 트리등의 계층적 데이터를 조회할 때 유용
  • 그래프 탐색
    • 그래프 구조의 데이터를 탐색하고 분석하는데 활용
  • 계층적 쿼리 연산
    • 계층적 데이터를 수정하거나 계산할 때 사용될 수 있음

쿼리

WITH RECURSIVE cte_count AS(
	SELECT 1      // Anchor Member
	UNION ALL
	SELECT n + 1  // Recursive Member
	FROM cte_count
	WHERE n < 3   // Termination Condition
)
SELECT n        // Query that uses CTE
FROM cte_count;
  • Anchor Member: 재귀를 시작하는 기본쿼리.
  • Recursive Member: 재귀적으로 반복되는 쿼리
  • Termination Condition: 재귀를 종료하는 조건

초기에는 최상위 매니저를 찾기 위한 기본 쿼리(Anchor Member)가 실행되고 그 후 재귀 쿼리(Recursive Member)가 매니저를 찾아 계속되서 실행된다.

📌 프로그래머스_멸종위기의 대장균 찾기

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

문제

각 세대별 자식이 없는 개체의 수(COUNT)와 세대(GENERATION)를 출력하는 SQL문을 작성해주세요. 이때 결과는 세대에 대해 오름차순 정렬해주세요. 단, 모든 세대에는 자식이 없는 개체가 적어도 1개체는 존재합니다.

Anchor Member

SELECT ID, PARENT_ID, 1 AS GENERATION
FROM ECOLI_DATA
WHERE PARENT_ID IS NULL

기본 쿼리는 최상위 매니저(최초의 대장균 개체) 를 찾기 위해 PARENT_ID 가 null인 개체를 찾는 쿼리문이다.

Recursive Member

SELECT E.ID, E.PARENT_ID, G.GENERATION + 1 AS GENERATION
FROM ECOLI_DATA E JOIN GEN G ON E.PARENT_ID = G.ID

ECOLI_DATA 테이블과 위에서 생성한 GEN 테이블을 JOIN 해서 합친후 재귀적인 방법으로 각 세대의 자식을 찾아 계산한다.

일반 쿼리

SELECT COUNT(*) COUNT, GENERATION
FROM GEN
WHERE ID NOT IN(
    SELECT DISTINCT PARENT_ID
    FROM ECOLI_DATA
    WHERE PARENT_ID IS NOT NULL
)
GROUP BY GENERATION
ORDER BY GENERATION;

자식이 없는 개체를 찾고 세대별로 개수를 카운트한다.

전체 쿼리

WITH RECURSIVE GEN AS(
    SELECT ID, PARENT_ID, 1 AS GENERATION
    FROM ECOLI_DATA
    WHERE PARENT_ID IS NULL
    
    UNION ALL
    
    SELECT E.ID, E.PARENT_ID, G.GENERATION + 1 AS GENERATION
    FROM ECOLI_DATA E JOIN GEN G ON E.PARENT_ID = G.ID
)
SELECT COUNT(*) COUNT, GENERATION
FROM GEN
WHERE ID NOT IN(
    SELECT DISTINCT PARENT_ID
    FROM ECOLI_DATA
    WHERE PARENT_ID IS NOT NULL
)
GROUP BY GENERATION
ORDER BY GENERATION;

 

출처
https://yermi.tistory.com/entry/MySQL-RECURSIVE-%EC%9E%AC%EA%B7%80%EC%A0%81%EC%9C%BC%EB%A1%9C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EC%A1%B0%ED%9A%8C%ED%95%98%EA%B8%B0-%EC%9E%AC%EA%B7%80-%EC%BF%BC%EB%A6%AC%EC%9D%98-%ED%99%9C%EC%9A%A9%EA%B3%BC-%EC%9D%B4%ED%95%B4
https://www.mysqltutorial.org/mysql-basics/mysql-recursive-cte/