În bazele de date relaționale, datele ierarhice (cum ar fi o structură de categorii cu sub-categorii la infinit sau o ierarhie de angajați și manageri) sunt dificil de extras: programatorii recurgeau adesea la zeci de interogări repetate din codul de aplicație (problema N+1).
Clauza WITH RECURSIVE permite definirea unui CTE (Common Table Expression) capabil să se auto-apeleze iterativ până la epuizarea tuturor nivelelor din arbore.
Structura constă din două părți legate prin `UNION ALL`: Termenul ancoră (interogarea de bază care selectează rădăcina arborelui) și Termenul recursiv (care face join între rândurile găsite la pasul anterior și restul tabelului), returnând întregul arbore ierarhic într-un singur tabel compact.
Sintaxă, opțiuni și concepte cheie
| Opțiune / Concept | Descriere practică |
|---|---|
WITH RECURSIVE |
Cuvintele cheie obligatorii ce inițializează mecanismul iterativ de calcul. |
Anchor Member (Termen ancoră) |
Interogarea inițială ce selectează primele înregistrări (ex. părintele de nivel 0). |
Recursive Member (Termen recursiv) |
Interogarea ce leagă rezultatele precedente de noile nivele copil prin join. |
UNION ALL |
Operatorul ce concatenează rezultatele fiecărei iterații până când nu se mai returnează rânduri noi. |
Exemple practice și cod
Exemplul 1: Extragerea arborelui complet de categorii imbricate cu indicarea nivelului de adâncime
Cum se traversează o structură de tip arbore în SQL pur.
WITH RECURSIVE arbore_categorii AS (
-- 1. Termenul ancoră: Categoriile principale (fără părinte)
SELECT id, nume, parinte_id, 1 AS nivel
FROM categorii
WHERE parinte_id IS NULL
UNION ALL
-- 2. Termenul recursiv: Copiii categoriilor găsite anterior
SELECT c.id, c.nume, c.parinte_id, ac.nivel + 1
FROM categorii c
INNER JOIN arbore_categorii ac ON c.parinte_id = ac.id
)
SELECT * FROM arbore_categorii ORDER BY nivel, nume;
-- Rezultat curat cu toate nivelele de sub-categorii:
Rezultat & Impact
Rezolvarea completă a ierarhiei într-o singură interogare executată nativ de motorul SQL.
Greșeli frecvente și bune practici
- Crearea unei bucle infinite în date (cicluri unde A este părintele lui B, iar B este părintele lui A) fără o clauză de protecție pe adâncime (`WHERE nivel < 10`).
- Utilizarea `UNION` în loc de `UNION ALL` fără un motiv întemeiat, ceea ce forțează eliminarea duplicatelor și încetinește enorm execuția.