PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

UPDATE avec jsonb_set() n'affecte qu'un seul objet dans le tableau imbriqué

Explication

La sous-sélection dans le FROM clause de votre UPDATE renvoie trois Lignes. Mais chaque ligne de la table cible ne peut être mise à jour qu'une fois en une seule UPDATE commande. Le résultat est que vous ne voyez que l'effet de un de ces trois lignes.

Ou, selon les termes de le manuel :

A part:n'appelez pas votre sous-requête "cte". Ce n'est pas une expression de table commune .

Bonne UPDATE

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<>violon ici

Utilisez jsonb_set() sur chaque objet (élément de tableau) avant de les agréger dans un tableau. D'abord au niveau des feuilles, puis de nouveau au niveau plus profond.

J'ai ajouté id comme PRIMARY KEY à la table. Nous avons besoin d'une colonne unique pour séparer les lignes.

Le ORDER BY ajouté peut être nécessaire ou non. Ajouté pour garantir la commande d'origine.

Bien sûr, si vos données sont aussi régulières que l'échantillon, une conception relationnelle avec des colonnes dédiées peut être une alternative plus simple. Voir