Ce face ARRAY, ANY() și unnest()
În PostgreSQL, orice tip de date nativ (integer, text, uuid, timestamptz) are automat și o variantă de tablou (integer[], text[] etc.). Tablourile sunt excelente pentru stocarea etichetelor (tags), a listelor de roluri sau pentru transmiterea unei liste de ID-uri ca un singur parametru pregătit (WHERE id = ANY($1::int[])).
Pentru a filtra rândurile pe baza elementelor dintr-un array poți folosi valoare = ANY(array) sau operatorii de mulțimi @> (conține toate elementele) și && (se intersectează / are cel puțin un element comun — ambele indexabile cu GIN). Funcția unnest() transformă un array în rânduri relaționale, iar ARRAY_AGG() face operația inversă.
Clauze, operatori și argumente
| Clauză / Operator | Descriere |
|---|---|
ARRAY['a', 'b'] sau '{a,b}'::text[] |
Construiește o valoare literală de tip tablou (în PostgreSQL indexarea tablourilor începe de la 1!). |
val = ANY(array) |
Returnează true dacă val este egal cu cel puțin un element din tablou (echivalent parametrizabil pentru IN (...)). |
array1 @> array2 |
Verifică dacă array1 conține toate elementele din array2 (suportă index GIN). |
array1 && array2 |
Operator de suprapunere (overlap): verifică dacă cele două tablouri au cel puțin un element comun (suportă index GIN). |
unnest(array) |
Funcție care despachetează un tablou și returnează câte un rând pentru fiecare element. |
ARRAY_AGG(DISTINCT col ORDER BY col) |
Funcție de agregare care colectează valorile unei coloane într-un tablou PostgreSQL. |
Exemple
Exemplul 1: Filtrarea articolelor după etichete (tags) cu ANY() și operatorul &&
Selectăm articolele care au fie eticheta postgresql, fie eticheta performanta în coloana etichete (de tip text[]).
SELECT id,
titlu,
etichete,
cardinality(etichete) AS nr_etichete
FROM articole
WHERE etichete && ARRAY['postgresql', 'performanta'];
Rezultat interogare
id | titlu | etichete | nr_etichete
-----+----------------------------------+---------------------------------+-------------
118 | Optimizarea indecșilor în PG 17 | {postgresql,indecsi,performanta}| 3
124 | Replicare logică pas cu pas | {postgresql,devops} | 2
(2 rows)
Exemplul 2: Despachetarea unui array în rânduri și numărarea frecvenței cu unnest()
Transformăm vectorul de etichete al fiecărui articol în rânduri individuale și calculăm câte articole folosesc fiecare etichetă.
SELECT eticheta,
COUNT(*) AS nr_articole
FROM articole
CROSS JOIN LATERAL unnest(etichete) AS eticheta
GROUP BY eticheta
ORDER BY nr_articole DESC, eticheta ASC;
Rezultat interogare
eticheta | nr_articole
-------------+-------------
postgresql | 18
performanta | 9
indecsi | 6
devops | 4
(4 rows)
Greșeli frecvente
- Atenție la indexarea de la 1: în PostgreSQL, primul element al unui tablou este
etichete[1], nuetichete[0]! - Folosirea
array_length(arr, 1)pe un tablou gol'{}'::text[]returneazăNULLîn loc de0; folosește întotdeauna funcțiacardinality(arr)care returnează corect0pentru un tablou gol.
Comenzi și funcții înrudite
JSONB și operatorii ->, ->>, @>, ?: Interoghează și filtrează documente binare JSONB folosind operatorii de extracție (->, ->>) și incluziune (@>, ?).CREATE INDEX (B-Tree, GIN, Partial, CONCURRENTLY): Creează indecși B-Tree, GIN (pentru JSONB și Array), indecși parțiali (WHERE) și indecși pe expresii fără blocarea scrierilor.JOIN și CROSS JOIN LATERAL: Unește tabele și permite subinterogărilor din FROM să facă referire la coloanele tabelelor precedente prin LATERAL.