Ce face generate_series()
generate_series() este una dintre cele mai îndrăgite funcții returnatoare de seturi (set-returning functions) din PostgreSQL. Poate genera secvențe numerice (int, bigint, numeric) sau secvențe de momente de timp (timestamp, timestamptz) între o valoare de început și una de sfârșit, cu un pas opțional.
În practică are două utilizări majore: completarea golurilor în rapoartele de tip serie temporală (făcând LEFT JOIN între un calendar generat cu generate_series și tabelul de comenzi ca să apară cu 0 și zilele fără vânzări) și generarea rapidă a milioanelor de rânduri sintetice pentru testarea performanței și a indecșilor.
Clauze, operatori și argumente
| Clauză / Operator | Descriere |
|---|---|
generate_series(start, stop) |
Generează numere întregi consecutive de la start până la stop inclusiv (cu pasul implicit 1). |
generate_series(start, stop, pas) |
Generează o serie numerică folosind pasul specificat (poate fi și negativ pentru numărare inversă). |
generate_series(ts_start, ts_stop, interval) |
Generează o serie de date/ore incrementate cu un interval (ex: '1 day', '1 hour', '1 month'). |
Exemple
Exemplul 1: Raport zilnic de vânzări fără zile lipsă (calendar cu LEFT JOIN)
Generăm toate zilele dintr-un interval și facem LEFT JOIN cu tabelul comenzi, astfel încât zilele cu zero comenzi să fie afișate cu 0 în loc să lipsească din grafic.
SELECT zi::date AS data_calendar,
COUNT(c.id) AS nr_comenzi,
COALESCE(SUM(c.total_lei), 0) AS vanzari_lei
FROM generate_series(
'2025-03-10'::timestamptz,
'2025-03-14'::timestamptz,
INTERVAL '1 day'
) AS zi
LEFT JOIN comenzi c
ON c.plasata_la >= zi
AND c.plasata_la < zi + INTERVAL '1 day'
GROUP BY zi
ORDER BY data_calendar;
Rezultat interogare
data_calendar | nr_comenzi | vanzari_lei
---------------+------------+-------------
2025-03-10 | 4 | 1420.00
2025-03-11 | 0 | 0.00
2025-03-12 | 2 | 530.00
2025-03-13 | 0 | 0.00
2025-03-14 | 5 | 2190.50
(5 rows)
Exemplul 2: Generarea rapidă a datelor de test într-un tabel cu INSERT … SELECT
Populăm un tabel de test cu 100.000 de rânduri realiste în mai puțin de o secundă folosind generate_series(1, 100000).
INSERT INTO evenimente_test (cod_eveniment, utilizator_id, creat_la)
SELECT 'EVT-' || LPAD(i::text, 6, '0'),
(i % 500) + 1,
NOW() - (i || ' minutes')::interval
FROM generate_series(1, 5) AS s(i)
RETURNING id, cod_eveniment, utilizator_id;
Rezultat interogare
id | cod_eveniment | utilizator_id
----+---------------+---------------
1 | EVT-000001 | 2
2 | EVT-000002 | 3
3 | EVT-000003 | 4
4 | EVT-000004 | 5
5 | EVT-000005 | 6
(5 rows)
INSERT 0 5
Greșeli frecvente
- Dacă
start > stopși pasul este pozitiv (saustart < stopcu pas negativ),generate_series()nu returnează o eroare, ci 0 rânduri. - La
LEFT JOINpe un calendar generat, nu pune condiții pe tabelul din dreapta în clauzaWHERE(ex:WHERE c.status = 'livrata'), deoarece vei anula efectul luiLEFT JOINși vei elimina din nou zilele cu zero comenzi; pune condiția în clauzaONsau înFILTER (WHERE ...).
Comenzi și funcții înrudite
NOW(), INTERVAL și date_trunc(): Lucrează cu momente de timp cu fus orar (timestamptz), aritmetică de durate (INTERVAL) și rotunjire calendaristică (date_trunc).to_char() și EXTRACT(): Formatează date, ore și numere în șiruri personalizate (to_char) sau extrage componente numerice din timestamp-uri (EXTRACT).COALESCE, NULLIF și CASE WHEN: Gestionează valorile NULL, previne împărțirea la zero și evaluează logica condițională direct în expresiile SQL.