sql >> Base de Datos >  >> RDS >> PostgreSQL

ACTUALIZAR con jsonb_set () solo afecta a un objeto en una matriz anidada

Explicación

La subselección en FROM cláusula de su UPDATE devuelve tres filas Pero cada fila en la tabla de destino solo se puede actualizar una vez en un solo UPDATE dominio. El resultado es que solo ves el efecto de one de esas tres filas.

O, en palabras de el manual :

Aparte:no llame a su subconsulta "cte". No es una expresión de tabla común .

Correcto 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<>fiddle aquí

Usa jsonb_set() en cada objeto (elemento de matriz) antes de volver a agregarlos en una matriz. Primero al nivel de la hoja y nuevamente al nivel más profundo.

Agregué id como PRIMARY KEY a la mesa. Necesitamos una columna única para mantener las filas separadas.

El ORDER BY agregado puede o no ser requerido. Se agregó para garantizar el pedido original.

Por supuesto, si sus datos son tan regulares como la muestra, un diseño relacional con columnas dedicadas podría ser una alternativa más simple. Ver