具有以下数据模型:
create table test
(
id int primary key,
js jsonb
);
insert into test values (1, '{"id": "total", "price": 400, "breakdown": [{"id": "product1", "price": 400}] }');
insert into test values (2, '{"id": "total", "price": 1000, "breakdown": [{"id": "product1", "price": 400}, {"id": "product2", "price": 600}]}');
我需要将所有价格键更新为新名称cost。在静态字段上很容易做到这一点,使用:
update test
set js = jsonb_set(js #- '{price}', '{cost}', js #> '{price}');
结果:
1 {"id": "total", "cost": 1000, "breakdown": [{"id": "product1", "price": 400}]}
2 {"id": "total", "cost": 2000, "breakdown": [{"id": "product1", "price": 400}, {"id": "product2", "price": 600}]}
但是我也需要在分解数组中做这些。
在不知道细分数组中的项目数的情况下,我如何做到这一点?换句话说,我如何在jsonb数组的每个元素上应用函数。
非常感谢。
将所有jsonb对象中的jsonb键替换为jsonb数组的另一种方法是:
我的查询分解了jsonb数组。对于每个对象,如果price
键存在,则从jsonb对象中删除price
键,使用旧的price
值添加新的键,然后使用修改后的对象创建一个新的jsonb数组。最后用新的替换旧的jsonb数组。
WITH cte AS (SELECT id, jsonb_agg(CASE WHEN item ? 'price'
THEN jsonb_set(item - 'price', '{"cost"}', item -> 'price')
ELSE item END) AS cost_array
FROM test
CROSS JOIN jsonb_array_elements(js -> 'breakdown') WITH ORDINALITY arr(item, index)
GROUP BY id)
UPDATE test
SET js = jsonb_set(js, '{breakdown}', cte.cost_array, false)
FROM cte
WHERE cte.id = test.id;
此查询是示例,易于更改字段:
您可以在dbfiddle中看到我的查询结构
update test u_t
set js = tmp.new_js
from (
select t.id,
(t.js || jsonb_build_object('cost', t.js ->> 'price')) - 'price'
||
jsonb_build_object('breakdown', jsonb_agg(
(b.value || jsonb_build_object('cost', b.value ->> 'price')) - 'price')) as new_js
from test t
cross join jsonb_array_elements(t.js -> 'breakdown') b
group by t.id) tmp
where u_t.id = tmp.id;
解决方案1:干净但沉重
首先创建一个类似于jsonb_set的聚合函数:
CREATE OR REPLACE FUNCTION jsonb_set(x jsonb, y jsonb, _path text[], _key text, _val jsonb, create_missing boolean DEFAULT True)
RETURNS jsonb LANGUAGE sql IMMUTABLE AS
$$
SELECT jsonb_set(COALESCE(x, y), COALESCE(_path, '{}' :: text[]) || _key, COALESCE(_val, 'null' :: jsonb), create_missing) ;
$$ ;
DROP AGGREGATE IF EXISTS jsonb_set_agg (jsonb, text[], text, jsonb, boolean) CASCADE ;
CREATE AGGREGATE jsonb_set_agg (jsonb, text[], text, jsonb, boolean)
(
sfunc = jsonb_set
, stype = jsonb
) ;
然后,在迭代jsonb数组元素时调用聚合函数:
WITH list AS (
SELECT id, jsonb_set_agg(js #- '{breakdown,' || ind || ',price}', '{breakdown,' || ind || ',cost}', js #> '{breakdown,' || ind || ',price}', true) AS js
FROM test
CROSS JOIN LATERAL generate_series(0, jsonb_array_length(js->'{breakdown}') - 1) AS ind
GROUP BY id)
UPDATE test AS t
SET js = jsonb_set(l.js #- '{price}', '{cost}', l.js #> '{price}')
FROM list AS l
WHERE t.id = l.id ;
解决方案2:又快又脏
您只需将jsonb转换为string,并将子字符串“price”替换为“cost”:
UPDATE test
SET js = replace(js :: text, 'price', 'cost') :: jsonb
在一般情况下,此解决方案将替换子字符串“价格”,即使在 jsonb 字符串值和包含子字符串“价格”的 jsonb 键中也是如此。为了降低风险,您可以将子字符串“price” :“替换为”成本“ :”,但风险仍然存在。
在我的Java项目中,我是usinq、JOOQ,我希望更新JSONB值。但我的建造失败了。 我写了一段代码: 我收到了下一条信息: 我犯错的地方?
如何更新JSONB以将新键添加到所有记录的嵌套数组(用于数组的所有项目)中。 我指的是表结构的链接: 给定的json是: 要将新元素添加到每个数组项中,请执行以下查询: 执行上述查询后输出: 但是上面只会在id=1的地方更新json。对于orders中的所有行,需要进行哪些更改才能更新与上述相同的JSON?
我正在使用(https://github.com/typeorm/typeorm)作为ORM库来连接postgresql数据库。我将几列保存为类型。现在我需要支持部分更新json数据,例如, 如果我只更新,我不想在更新语句中覆盖lastName。支持,我可以使用它来部分更新字段,但我如何使它与图书一起工作?
我正在创建一个递归导航迷宫的程序。代码: 然而,每当我到达死胡同时,它都不会回溯。当我调试时,它表明当程序从递归或“回溯”返回时,我的起始值专注于停留在我的死胡同空间。 例如: 9是我的出发点。2是我的退出。4是我的道路。1 表示墙壁。当我到达一个死胡同时(在本例中为第 7 行,第 2 列)。我的立场是等于整个程序其余部分的死胡同空间。这是为什么呢?
问题内容: PostgreSQL 9.1 经营状况 每个月,都会为特定的流程分配一批新的帐户。可以按月份,帐户数和帐户总余额来描述每批。该过程的目标是从客户那里收回一些余额。然后每月分别跟踪每个批次(自将批次转移到流程以来,每个月回收的金额)。 目标 我的目标是预测将来将回收多少。 资料定义 样本数据 计算过程 您可以将数据想象成一个三角形矩阵(将预测X值): 算法 我的目标是预测所有遗漏的点(未
每次我执行INSERT或UPSERT(ON CONFLICT UPDATE)时,每个表上的增量列都会增加之前的更新数量。 例如,如果我有这张表: 然后运行这些查询: 这是一个相当大的问题。我们运行的脚本每天处理100000个通知。这会在每一次插入之间产生大约10000行的间隙,所以我们可能从100行开始,但当我们达到1000行时,最后一行的主键ID值会自动增加到100000以上。 如果这种情况继续