2016-06-28 17 views
2

私はPostgreSQL 9.4.5を使用しています。 更新jsonb欄にお願いします。PostgreSQLでjsonbの文字列を更新するには?

私のテーブルがこのように構成されています

CREATE TABLE my_table (
    gid serial PRIMARY KEY, 
    "data" jsonb 
); 

JSON文字列は、このようなものです:

{"files": [], "ident": {"id": 1, "country": null, "type ": "20"}} 

次のSQLは、ジョブ(構文エラー - SQL状態= 42601)を行いません。

UPDATE my_table SET "data" -> 'ident' -> 'country' = 'Belgium'; 

これを達成する方法はありますか?

+1

UPDATE my_table SET "data" = jsonb_set( "data"、 "{" ident "、" country "}"、 "Belgium" '); ' – Abelisto

+0

実際に複製された:新しいPostgreSQL JSONデータ型の中で?](http://stackoverflow.com/q/18209625/593144) – Abelisto

+0

私は同意しますが、 ( '' jsonb''ではなく) '' json''型に関するものです。 Answersは 'jsonb'を広く参照しています。 – wiltomap

答えて

-1

私の以前のソリューションは9.5の機能に依存していました。

以下のabelistoのソリューションに行くか、pl/perlu、plpythonu、またはplv8jsを使用してjsonのミューテータをより適切にサポートする言語で記述することをお勧めします。

+0

クエリでエラーメッセージが返されます。* fonction jsonb_build_object(不明、不明)が存在しません。* – wiltomap

+0

申し訳ありません。ドキュメントを誤読し、json_build_objectにしてから最終結果をjsonbにキャストしてください。編集。 –

+0

hmmm ||また、9.5のみです。 –

0

PG 9.4では、jsonb_set()(9.5)などの「簡単な」ソリューションが不足しています。あなたの唯一の選択肢はJSONオブジェクトを解凍し、変更を加えてオブジェクトを再構築することです。 JSONは、組み込み関数の高度化や精巧さにかかわらず、操作するのは恐ろしいことです。 SELECT"data"->'ident'

CREATE TYPE data_ident AS (id integer, country text, "type" integer); 

UPDATE my_table 
SET "data" = json_build_object('files', "data"->'files', 'ident', ident.j)::jsonb 
FROM (
    SELECT gid, json_build_object('id', j.id, 'country', 'Belgium', 'type', j."type") AS j 
    FROM my_table 
    JOIN LATERAL jsonb_populate_record(null::data_ident, "data"->'ident') j ON true) ident 
WHERE my_table.gid = ident.gid; 

は(あなたが CREATE TYPE構造に必要があるため)レコードに展開されます。新しい国名のJSONオブジェクトに組み込まれています。 UPDATEでは、 "ident"オブジェクトが "files"オブジェクトに再結合され、全体が jsonbにキャストされます。 -

美の純粋なものの二つの機能だけであれば、速度があなたのものではありませんよう...

+0

IMOあなたのソリューションの主な欠点は、異なるかもしれない最初の構造に注意を払わずにオブジェクト全体を再構築することです。 – Abelisto

1

[OK]をあります

create or replace function set_jsonb_value(p_j jsonb, p_key text, p_value jsonb) returns jsonb as $$ 
    select jsonb_object_agg(t.key, t.value) from (
    select 
     key, 
     case 
     when jsonb_typeof(value) = 'object' then set_jsonb_value(value, p_key, p_value) 
     when key = p_key then p_value 
     else value 
     end as value from jsonb_each(p_j)) as t; 
$$ language sql immutable; 

は最初のものは、単に既存のキーの値を変更します関係なく、キーパスの:

postgres=# select set_jsonb_value(
    '{"files": [], "country": null, "ident": {"id": 1, "country": null, "type ": "20"}}', 
    'country', 
    '"foo"'); 
            set_jsonb_value          
-------------------------------------------------------------------------------------- 
{"files": [], "ident": {"id": 1, "type ": "20", "country": "foo"}, "country": "foo"} 
(1 row) 


create or replace function set_jsonb_value(p_j jsonb, p_path text[], p_value jsonb) returns jsonb as $$ 
    select jsonb_object_agg(t.key, t.value) from (
    select 
     key, 
     case 
     when jsonb_typeof(value) = 'object' then set_jsonb_value(value, p_path[2:1000], p_value) 
     when key = p_path[1] then p_value 
     else value 
     end as value from jsonb_each(p_j) 
    union all 
    select 
     p_path[1], 
     case 
     when array_length(p_path,1) = 1 then p_value 
     else set_jsonb_value('{}', p_path[2:1000], p_value) end 
    where not p_j ? p_path[1]) as t; 
$$ language sql immutable; 

2つ目は、指定されたパスを使用して、既存のキーの値を変更するか、パスが存在しない場合は、それを作成します。テスト済み:

postgres=# select set_jsonb_value(
    '{"files": [], "country": null, "ident": {"id": 1, "type ": "20"}}', 
    '{ident,country}'::text[], 
    '"foo"'); 
            set_jsonb_value         
------------------------------------------------------------------------------------- 
{"files": [], "ident": {"id": 1, "type ": "20", "country": "foo"}, "country": null} 
(1 row) 

postgres=# select set_jsonb_value(
    '{"files": [], "country": null, "ident": {"id": 1, "type ": "20"}}', 
    '{ident,foo,bar,country}'::text[], 
    '"foo"'); 
              set_jsonb_value            
------------------------------------------------------------------------------------------------------- 
{"files": [], "ident": {"id": 1, "foo": {"bar": {"country": "foo"}}, "type ": "20"}, "country": null} 
(1 row) 

は、PostgreSQLの< 9.5
免責事項を使用して誰かに役立ちます願っていますPostgreSQL 9.5

関連する問題