簡體   English   中英

更新 Postgres 13 中的部分 jsonb 字段

[英]Update partial jsonb field in Postgres 13

任何人都可以幫助優化 SQL 請求 Postgres 13 (jsonb)。

需要用指定的 ID 更新 Jsonb 字段內的“百分比”值

此示例正在運行,但它在大型數據庫上運行了很長時間。

select version();

CREATE TABLE collection (
    ID serial NOT NULL PRIMARY KEY,
    info jsonb NOT NULL
);

INSERT INTO collection (info)
VALUES
    (
        '[{"id": "1", "percent": "1"}, {"id": "6", "percent": "2"}]'
    ),
    (
        '[{"id": "5", "percent": "3"}, {"id": "1", "percent": "4"}]'
    ),
    (
        '[{"id": "1", "percent": "5"}, {"id": "2", "percent": "5"}, {"id": "3", "percent": "5"}]'
    );
    
UPDATE collection
                SET info = array_to_json(ARRAY(SELECT jsonb_set(x.original_info,
                                               '{percent}',
                                                 (
                                                     CASE
                                                         WHEN x.original_info ->> 'id' = '1'
                                                             THEN '25'
                                                         ELSE
                                                             concat('"',
                                                                    x.original_info ->> 'percent',
                                                                    '"')
                                                         END
                                                      )::jsonb)
                                        FROM (SELECT jsonb_array_elements(collection.info) original_info) x))::jsonb;

https://dbfiddle.uk/?rdbms=postgres_13&fiddle=a521fee551f2cdf8b189ef0c0191b730

我將其表述為:

update collection c
set info = (
    select jsonb_agg(
        case when obj ->> 'id' = '1' 
            then x.obj - '{percent}' || '{"percent": "25"}' 
            else x.obj
        end
        order by x.rn
    )
    from  jsonb_array_elements(c.info) with ordinality as x(obj, rn)
)

邏輯與原始代碼中的邏輯完全相同,但這會跳過一些不必要的強制轉換,並使用直接 json 數組聚合而不是中間數組轉換。 另外,我使用了 json 運算符而不是jsonb_set()

另一個重要的一點是,這保留了原始 json 數組中對象的順序 - 而您的原始代碼沒有。

如果表中有很多行沒有 object 有您搜索的 id,那么我們可以預先過濾數據以僅更新相關行。 為此,您可以執行以下操作:

update collection c
set info = c1.info
from (
    select c.id, 
        jsonb_agg(
            case when obj ->> 'id' = '1' 
                then x.obj - '{percent}' || '{"percent": "25"}' 
                else x.obj
            end
            order by x.rn
        ) as info
    from collection c 
    cross join lateral jsonb_array_elements(c.info) with ordinality as x(obj, rn)
    group by c.id
    having bool_or(obj ->> 'id' = '1' )
) c1
where c1.id = c.id

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM