将 json 数组的每个项目的值与 postgres 9.6 相乘

multiply a value of each item of a json array with postgres 9.6

我尝试了很多不同的东西,我在这里和那里收集了很多东西(官方文档,博客文章,所以,......)但没有成功,所以我的问题是:


鉴于此 table:

basik=# select id, jsonb_pretty(range_price_list_values::jsonb) from product;
                  id                  |       jsonb_pretty
--------------------------------------+--------------------------
 cc80c862-c264-4bfe-a929-a52478c8d59e | [                       +
                                      |     {                   +
                                      |         "to": 10,       +
                                      |         "from": 5,      +
                                      |         "price": 1      +
                                      |     },                  +
                                      |     {                   +
                                      |         "to": 20,       +
                                      |         "from": 15,     +
                                      |         "price": 1298000+
                                      |     },                  +
                                      |     {                   +
                                      |         "to": 30,       +
                                      |         "from": 25,     +
                                      |         "price": 500000 +
                                      |     }                   +
                                      | ]

如何将table的每一行的每个元素的price键乘以1000?


PS:我的 失败 暂定是查看 jsonb_* 函数和 window 函数:

WITH prices as (select id, jsonb_array_elements(range_price_list_values::jsonb) from product)

UPDATE product SET range_price_list_values = JSONB_SET(
    range_price_list_values::jsonb,
    '{' || price.rank || ',price}', jsonb_extract_path('{' || price.rank || ',price}')::int * 1000, false
)::json;

感谢您抽出时间阅读! :)

第一个来的(很丑):

t=# create table product (id text, range_price_list_values jsonb);
CREATE TABLE
t=# insert into product select 'cc80c862-c264-4bfe-a929-a52478c8d59e','[
t'#   {
t'#       "to": 10,
t'#       "from": 5,
t'#       "price": 1
t'#   },
t'#   {
t'#       "to": 20,
t'#       "from": 15,
t'#       "price": 1298000
t'#   },
t'#   {
t'#       "to": 30,
t'#       "from": 25,
t'#       "price": 500000
t'#   }
t'# ]';
INSERT 0 1

t=#  with b as (with a as (select id, jsonb_array_elements(range_price_list_values::jsonb) j from product) select id,jsonb_set(j,'{price}',((j->>'price')::int * 1000)::text::jsonb) from a) select distinct id, jsonb_pretty(concat('[',string_agg(jsonb_set::text,',') over (partition by id),']')::jsonb) from b;
                  id                  |        jsonb_pretty
--------------------------------------+-----------------------------
 cc80c862-c264-4bfe-a929-a52478c8d59e | [                          +
                                      |     {                      +
                                      |         "to": 10,          +
                                      |         "from": 5,         +
                                      |         "price": 1000      +
                                      |     },                     +
                                      |     {                      +
                                      |         "to": 20,          +
                                      |         "from": 15,        +
                                      |         "price": 1298000000+
                                      |     },                     +
                                      |     {                      +
                                      |         "to": 30,          +
                                      |         "from": 25,        +
                                      |         "price": 500000000 +
                                      |     }                      +
                                      | ]
(1 row)

在 CTE 中有了它,您可以根据它更新值

您需要一个子 select,因为您想要更新 JSON 中的多个字段:

update product
set    range_price_list_values = (
         select jsonb_agg(case
                  when jsonb_typeof(elem -> 'price') = 'number'
                  then jsonb_set(elem, array['price'], to_jsonb((elem ->> 'price')::numeric * 1000))
                  else elem
                end)
         from   jsonb_array_elements(range_price_list_values::jsonb) elem
       )::json;

注意:这只会更新数字 price 键,否则当价格不是数字时会抛出异常。

http://rextester.com/PQN70851