json_group_array / json_group_object în SQLite

Funcții JSON SQLite 3.10.0

Funcții de agregare care adună valorile dintr-un grup de rânduri într-un tablou sau obiect JSON, gata de trimis unui API.

Sintaxă
json_group_array(valoare)
json_group_object(cheie, valoare)
json_object(cheie1, valoare1, ...)
json_array(valoare1, valoare2, ...)

Ce face json_group_array / json_group_object

json_group_array(x) este o funcție de agregare, ca COUNT sau SUM: pentru fiecare grup din GROUP BY întoarce un tablou JSON cu valorile lui x. json_group_object(cheie, valoare) întoarce un obiect JSON în care fiecare rând devine o pereche cheie–valoare. Ambele au apărut în SQLite 3.10.0.

json_object și json_array construiesc un singur obiect sau tablou din argumentele primite. Combinate cu funcțiile de grup, poți produce direct din SQL un document JSON imbricat. SQLite ține minte că rezultatul acestor funcții este JSON, așa că un obiect pus direct în alt obiect nu este transformat în text cu ghilimele. Informația aceasta se pierde însă când valoarea este salvată într-un tabel sau trece printr-un CTE: acolo folosește json(valoare).

Din 3.44.0 poți scrie ORDER BY în interiorul apelului, de exemplu json_group_array(nume ORDER BY nume), ca ordinea elementelor din tablou să fie sigură. Textele obișnuite sunt puse în JSON ca texte, cu ghilimele; ca să pui un text care conține deja JSON, trece-l prin json().

Parametri

Parametru Descriere
valoare Valoarea adăugată pentru fiecare rând; NULL devine null în tablou.
cheie La json_group_object: textul folosit ca nume de cheie.

Ce returnează

Text JSON: un tablou (json_group_array) sau un obiect (json_group_object).

Exemple

Exemplele de pe această pagină pornesc de la datele de mai jos. Rulează mai întâi acest cod, apoi exemplul.

CREATE TABLE elevi (
  nume  TEXT NOT NULL,
  clasa TEXT NOT NULL,
  nota  INTEGER NOT NULL
);
INSERT INTO elevi VALUES
  ('Ana', '9A', 10), ('Mihai', '9A', 8),
  ('Ioana', '9B', 9), ('Dan', '9B', 7), ('Mara', '9B', 10);

Exemplul 1: Un tablou de nume pentru fiecare clasă

ORDER BY nume în interiorul apelului ordonează alfabetic elementele tabloului.

SELECT clasa, json_group_array(nume ORDER BY nume) AS elevi
FROM elevi
GROUP BY clasa
ORDER BY clasa;

Rezultat

╭───────┬────────────────────────╮
│ clasa │         elevi          │
╞═══════╪════════════════════════╡
│ 9A    │ ["Ana","Mihai"]        │
│ 9B    │ ["Dan","Ioana","Mara"] │
╰───────┴────────────────────────╯

Exemplul 2: Un obiect nume → notă

Fără GROUP BY, toate rândurile formează un singur grup, deci rezultă un singur obiect.

SELECT json_group_object(nume, nota ORDER BY nume) AS note
FROM elevi
WHERE clasa = '9B';

Rezultat

╭───────────────────────────────╮
│             note              │
╞═══════════════════════════════╡
│ {"Dan":7,"Ioana":9,"Mara":10} │
╰───────────────────────────────╯

Exemplul 3: Răspuns JSON imbricat, gata pentru un API

Fiecare elev devine un obiect cu json_object, obiectele sunt adunate în tablou pe clasă, apoi clasele sunt adunate într-un tablou final. Când o valoare JSON trece printr-un CTE (sau este citită dintr-un tabel), SQLite uită că e JSON și ar pune-o ca text cu ghilimele; json(obiect) o marchează din nou ca JSON.

WITH pe_clasa AS (
  SELECT clasa, json_object(
           'clasa', clasa,
           'medie', round(AVG(nota), 2),
           'elevi', json_group_array(json_object('nume', nume, 'nota', nota) ORDER BY nume)
         ) AS obiect
  FROM elevi
  GROUP BY clasa
)
SELECT json_group_array(json(obiect) ORDER BY clasa) AS raspuns FROM pe_clasa;

Rezultat

╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│                                                                                                   raspuns                                                                                                   │
╞═════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ [{"clasa":"9A","medie":9.0,"elevi":[{"nume":"Ana","nota":10},{"nume":"Mihai","nota":8}]},{"clasa":"9B","medie":8.67,"elevi":[{"nume":"Dan","nota":7},{"nume":"Ioana","nota":9},{"nume":"Mara","nota":10}]}] │
╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

Greșeli frecvente

  • Pui un text care conține JSON direct în json_object sau json_group_array, de exemplu dintr-o coloană TEXT. Este tratat ca text și apare între ghilimele, cu \"; trece-l întâi prin json(coloana).
  • Te bazezi pe ordinea elementelor fără ORDER BY în apel. Ordinea depinde de cum citește SQLite rândurile și se poate schimba.
  • Folosești json_group_object cu chei care se repetă. Obiectul rezultat va avea chei duplicate, pe care multe biblioteci JSON le citesc păstrând doar ultima valoare.

Comenzi înrudite

  • group_concat / string_agg: Lipește într-un singur text valorile dintr-un grup de rânduri, cu separatorul ales, de exemplu toți elevii unui curs.
  • 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.
  • json_set / json_insert / json_replace / json_remove: Modifică un document JSON: adaugă sau schimbă chei, adaugă la un tablou, șterge chei, și întoarce documentul nou.
  • SQLite din Python (sqlite3): Modulul sqlite3 din biblioteca standard Python: conectare, interogări cu parametri, tranzacții și rânduri ca dicționare.