PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

UPDATE con jsonb_set() interessa solo un oggetto nell'array nidificato

Spiegazione

La sottoselezione nel FROM clausola del tuo UPDATE restituisce tre righe. Ma ogni riga nella tabella di destinazione può essere aggiornata solo una volta in un unico UPDATE comando. Il risultato è che vedi solo l'effetto di uno di queste tre righe.

Oppure, nelle parole del il manuale :

A parte:non chiamare la tua sottoquery "cte". Non è un Espressione di tabella comune .

UPDATE corretto

UPDATE table_ t
SET    value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM  (
   SELECT id
        , jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)
                    ORDER BY idx1) AS new_prop
   FROM  (
      SELECT t.id, arr1.prop, arr1.idx1
           , jsonb_agg(jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
                       ORDER BY idx2) AS new_rules
      FROM table_ t
         , jsonb_array_elements(value_->'iProps')       WITH ORDINALITY arr1(prop,idx1)
         , jsonb_array_elements(prop->'value'->'rules') WITH ORDINALITY arr2(rule,idx2)
      GROUP  BY t.id, arr1.prop, arr1.idx1
      ) sub1
   GROUP  BY id
   ) sub2
WHERE t.id = sub2.id;

db<>violino qui

Usa jsonb_set() su ciascun oggetto (elemento array) prima di aggregarli nuovamente in un array. Prima a livello fogliare e poi ancora a livello più profondo.

Ho aggiunto id come PRIMARY KEY al tavolo. Abbiamo bisogno di una colonna univoca per mantenere le righe separate.

Il ORDER BY aggiunto può o non può essere richiesto. Aggiunto per garantire l'ordine originale.

Ovviamente, se i tuoi dati sono regolari come il campione, un design relazionale con colonne dedicate potrebbe essere un'alternativa più semplice. Vedi