Ce face WITH RECURSIVE
Un CTE recursiv are două părți legate prin UNION ALL (sau UNION). Prima parte dă rândurile de pornire. A doua parte citește din CTE-ul însuși și produce rânduri noi pornind de la cele găsite deja. SQLite repetă pasul recursiv până când acesta nu mai produce niciun rând.
SQLite ține rândurile de prelucrat într-o coadă: implicit le ia în ordinea în care au apărut (parcurgere în lățime). Dacă pasul recursiv are ORDER BY, coada devine o coadă cu priorități, așa că poți obține de exemplu o parcurgere în adâncime a unui arbore. LIMIT în pasul recursiv oprește generarea după un număr de rânduri.
Cu UNION în loc de UNION ALL, rândurile duplicate sunt eliminate, ceea ce oprește ciclurile într-un graf. În pasul recursiv nu poți folosi funcții de agregare sau funcții fereastră.
Parametri
| Parametru | Descriere |
|---|---|
pasul inițial |
SELECT-ul care nu citește din CTE: rândurile de pornire. |
pasul recursiv |
SELECT-ul care citește din CTE și produce rândurile următoare; trebuie să aibă o condiție de oprire. |
Exemple
Exemplul 1: Numerele de la 1 la 5
Pornim de la 1 și adăugăm 1 cât timp x < 5. Când condiția devine falsă, pasul recursiv nu mai produce rânduri și generarea se oprește.
WITH RECURSIVE numere (x) AS (
SELECT 1
UNION ALL
SELECT x + 1 FROM numere WHERE x < 5
)
SELECT x, x * x AS patrat FROM numere;
Rezultat
╭───┬────────╮
│ x │ patrat │
╞═══╪════════╡
│ 1 │ 1 │
│ 2 │ 4 │
│ 3 │ 9 │
│ 4 │ 16 │
│ 5 │ 25 │
╰───┴────────╯
Exemplul 2: Toate zilele unei săptămâni
Seria de date pornește de luni, 26 octombrie 2026. strftime('%w') dă ziua săptămânii (0 = duminică); CASE o transformă în nume românesc.
WITH RECURSIVE zile (zi) AS (
SELECT '2026-10-26'
UNION ALL
SELECT date(zi, '+1 day') FROM zile WHERE zi < '2026-11-01'
)
SELECT zi,
CASE strftime('%w', zi)
WHEN '0' THEN 'duminică' WHEN '1' THEN 'luni' WHEN '2' THEN 'marți'
WHEN '3' THEN 'miercuri' WHEN '4' THEN 'joi' WHEN '5' THEN 'vineri'
ELSE 'sâmbătă'
END AS nume_zi
FROM zile;
Rezultat
╭────────────┬──────────╮
│ zi │ nume_zi │
╞════════════╪══════════╡
│ 2026-10-26 │ luni │
│ 2026-10-27 │ marți │
│ 2026-10-28 │ miercuri │
│ 2026-10-29 │ joi │
│ 2026-10-30 │ vineri │
│ 2026-10-31 │ sâmbătă │
│ 2026-11-01 │ duminică │
╰────────────┴──────────╯
Exemplul 3: Organigrama unei firme
Pornim de la directoare (fără șef) și coborâm câte un nivel. Coloana cale păstrează drumul de la vârf; ordonând după ea, fiecare angajat apare sub șeful lui.
CREATE TABLE angajati (id INTEGER PRIMARY KEY, nume TEXT, sef_id INTEGER);
INSERT INTO angajati VALUES
(1, 'Ana (directoare)', NULL),
(2, 'Radu', 1), (3, 'Elena', 1),
(4, 'Dan', 2), (5, 'Mara', 2), (6, 'Ioana', 3);
WITH RECURSIVE ierarhie (id, nume, nivel, cale) AS (
SELECT id, nume, 0, nume FROM angajati WHERE sef_id IS NULL
UNION ALL
SELECT a.id, a.nume, i.nivel + 1, i.cale || ' > ' || a.nume
FROM angajati a JOIN ierarhie i ON a.sef_id = i.id
)
SELECT nivel, cale FROM ierarhie ORDER BY cale;
Rezultat
╭───────┬──────────────────────────────────╮
│ nivel │ cale │
╞═══════╪══════════════════════════════════╡
│ 0 │ Ana (directoare) │
│ 1 │ Ana (directoare) > Elena │
│ 2 │ Ana (directoare) > Elena > Ioana │
│ 1 │ Ana (directoare) > Radu │
│ 2 │ Ana (directoare) > Radu > Dan │
│ 2 │ Ana (directoare) > Radu > Mara │
╰───────┴──────────────────────────────────╯
Greșeli frecvente
- Uiți condiția de oprire din pasul recursiv. Interogarea generează rânduri la nesfârșit; pune un
WHEREsau, la testare, unLIMITîn interogarea principală. - Folosești
UNION ALLpe un graf cu cicluri (A trimite la B, B la A). Rândurile se repetă la infinit; foloseșteUNIONsau ține o cale și verifică dacă nodul apare deja în ea. - Pui
COUNT()sauSUM()în pasul recursiv. SQLite nu permite agregări acolo; fă agregarea în interogarea principală, după CTE.
Comenzi înrudite
WITH (CTE): Dă un nume unei subinterogări (Common Table Expression) și o folosește apoi ca pe un tabel, ca interogarea să fie mai ușor de citit.date, time, datetime: Transformă și calculează date: extrage ziua sau ora, adună zile și luni, găsește începutul lunii sau lunea următoare.strftime: Formatează o dată după un șablon ales de tine (de exemplu 25.10.2026 09:05) sau extrage din ea anul, luna, ziua săptămânii.json_each / json_tree: Transformă un tablou sau un obiect JSON în rânduri, ca să poți filtra, număra și lega elementele lui cu alte tabele.