ARRAY, ANY() și unnest() în PostgreSQL

JSONB, Array și tipuri avansate PostgreSQL 8.2+ (standard în PostgreSQL 15–17)

Stochează și manipulează tablouri tipizate (text[], int[]), verifică apartenența cu ANY() și le extinde în rânduri cu unnest().

Sintaxă SQL
SELECT * FROM tabel WHERE 'valoare' = ANY(coloana_array);nSELECT id, elem FROM tabel CROSS JOIN LATERAL unnest(coloana_array) AS elem;

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], nu etichete[0]!
  • Folosirea array_length(arr, 1) pe un tablou gol '{}'::text[] returnează NULL în loc de 0; folosește întotdeauna funcția cardinality(arr) care returnează corect 0 pentru un tablou gol.

Comenzi și funcții înrudite