CodeGym /Corsi /SQL SELF /Esempi di query complesse con JSONB

Esempi di query complesse con JSONB

SQL SELF
Livello 34 , Lezione 2
Disponibile

Nelle lezioni precedenti abbiamo visto le basi di JSONB: come creare, modificare ed estrarre dati. Ora è il momento delle vere sfide — query complesse che ti faranno vedere tutta la potenza di questo tipo di dato.

Immagina un negozio online con un catalogo di prodotti. Ogni prodotto ha info base (nome, ID), ma le caratteristiche possono essere molto diverse: un laptop ha RAM e CPU, i vestiti — taglie e materiali, i libri — autori e generi. Salvare tutto in tabelle separate? Scomodo. In JSONB? Perfetto! Ma come trovi tutti i prodotti di un certo brand, li ordini per prezzo o calcoli statistiche per categoria? Come lavori con dati che non sono in colonne normali, ma nascosti dentro una struttura JSON?

Oggi vediamo scenari reali: dal filtraggio semplice a query complesse con raggruppamento e aggregazione. Vedrai come JSONB trasforma PostgreSQL in uno strumento super flessibile per qualsiasi tipo di dato.

Filtraggio dei dati in JSONB

Filtrare i dati è come usare un colino per il tè: tieni solo quello che ti serve e togli il resto. Con JSONB è ancora più interessante, perché puoi filtrare non solo sulle colonne normali, ma anche su dati nascosti in profondità nella struttura JSON.

Operatori per filtrare JSONB:

  • @> — "JSONB-contiene". Controlla se l’oggetto JSONB contiene il sottoinsieme specificato.
  • ? — "Chiave presente". Controlla se la chiave specificata esiste nell’oggetto JSONB.
  • ?| — "Almeno una chiave presente". Controlla se almeno una delle chiavi specificate esiste.
  • ?& — "Tutte le chiavi presenti". Controlla che tutte le chiavi specificate esistano.

Esempio: filtrare per chiave e valore. Supponiamo di avere una tabella products con una colonna details che salva info JSONB sui prodotti:

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name TEXT,
    details JSONB
);

Esempio di dati:

INSERT INTO products (name, details) VALUES
('Laptop', '{"brand": "Dell", "price": 1200, "specs": {"ram": "16GB", "cpu": "i7"}}'),
('Smartphone', '{"brand": "Apple", "price": 800, "specs": {"ram": "4GB", "cpu": "A15"}}'),
('Tablet', '{"brand": "Samsung", "price": 500, "specs": {"ram": "8GB", "cpu": "Exynos"}}');

Risultato:

id name details
1 Laptop {"brand": "Dell", "price": 1200, "specs": {"ram": "16GB", "cpu": "i7"}}
2 Smartphone {"brand": "Apple", "price": 800, "specs": {"ram": "4GB", "cpu": "A15"}}
3 Tablet {"brand": "Samsung", "price": 500, "specs": {"ram": "8GB", "cpu": "Exynos"}}

Per trovare tutti i prodotti con brand "Apple":

SELECT *
FROM products 
WHERE details @> '{"brand": "Apple"}';

Risultato:

id name details
2 Smartphone {"brand": "Apple", "price": 800, "specs": {"ram": "4GB", "cpu": "A15"}}

Se vuoi trovare tutti i prodotti che hanno la chiave specs, usa l’operatore ?:

SELECT *
FROM products 
WHERE details ? 'specs';

Risultato:

id name details
1 Laptop {"brand": "Dell", "price": 1200, "specs": {"ram": "16GB", "cpu": "i7"}}
2 Smartphone {"brand": "Apple", "price": 800, "specs": {"ram": "4GB", "cpu": "A15"}}
3 Tablet {"brand": "Samsung", "price": 500, "specs": {"ram": "8GB", "cpu": "Exynos"}}

Tutte le righe hanno il campo details e la chiave specs.

Ordinamento dei dati in JSONB

A volte ti serve ordinare i dati non sulle colonne normali, ma sui valori che stanno dentro JSONB. Per farlo puoi usare gli operatori ->> (estrae il valore come testo) e CAST per convertire il testo nel tipo che ti serve.

Esempio: ordiniamo i prodotti per prezzo:

SELECT *
FROM products 
ORDER BY (details->>'price')::INTEGER;

Risultato:

id name details
3 Tablet {"brand": "Samsung", "price": 500, "specs": {"ram": "8GB", "cpu": "Exynos"}}
2 Smartphone {"brand": "Apple", "price": 800, "specs": {"ram": "4GB", "cpu": "A15"}}
1 Laptop {"brand": "Dell", "price": 1200, "specs": {"ram": "16GB", "cpu": "i7"}}

Raggruppamento dei dati in JSONB

Il raggruppamento ti permette di aggregare dati e mostrare statistiche. Ad esempio, puoi vedere quanti prodotti ci sono per ogni brand.

Esempio: contiamo quanti prodotti ci sono per ogni brand:

SELECT
    details->>'brand' AS brand,
    COUNT(*) AS product_count
FROM products
GROUP BY details->>'brand';

Risultato:

brand product_count
Dell 1
Apple 1
Samsung 1

Esempi pratici

Filtraggio e raggruppamento. Contiamo quanti prodotti costano più di 600 per ogni brand:

SELECT
    details->>'brand' AS brand,
    COUNT(*) AS product_count
FROM products
WHERE (details->>'price')::INTEGER > 600
GROUP BY details->>'brand';

Risultato:

brand product_count
Dell 1
Apple 1

Ordinamento dopo il raggruppamento. Ora ordiniamo i brand per numero di prodotti:

SELECT
    details->>'brand' AS brand,
    COUNT(*) AS product_count
FROM products
GROUP BY details->>'brand'
ORDER BY product_count DESC;

Query complessa: filtraggio, ordinamento, raggruppamento

Immagina di voler trovare i brand che hanno prodotti sopra i 600 e scegliere il prodotto più economico per ogni brand. Ecco come si fa:

WITH filtered_products AS (
    SELECT *
    FROM products
    WHERE (details->>'price')::INTEGER > 600
)
SELECT
    details->>'brand' AS brand,
    MIN((details->>'price')::INTEGER) AS min_price
FROM filtered_products
GROUP BY details->>'brand'
ORDER BY min_price;

Risultato:

brand min_price
Apple 800
Dell 1200

Errori tipici e consigli

Errore: Uso sbagliato degli operatori. Non confondere gli operatori -> e ->>: il primo restituisce un oggetto, il secondo — un valore testo.

Errore: Problemi di performance. Se fai spesso query complesse, crea un indice GIN sulla colonna JSONB.

Errore: Problemi di tipo. I valori da JSONB sono stringhe, quindi ricordati di usare CAST.

Esempio di creazione indice:

CREATE INDEX idx_products_details ON products USING GIN (details);

Ora il filtraggio tipo details @> '{"brand": "Apple"}' andrà molto più veloce.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION