Postgresテーブル_my_table
_にjsonb
列data
があります。次のデータが含まれています。
_[
{"id":"1","status":"test status1","updatedAt":"1571145003"},
{"id":"2","status":"test status2","updatedAt":"1571145323"}
]
_
1つのクエリを使用して、その配列内のすべてのオブジェクトのupdatedAt
キーを更新したいと思います。私は試した:
_update my_table set data = data || '{"updatedAt": "1571150000"}';
_
上記のクエリは、次のように配列内に新しいオブジェクトを追加しました。
_[
{"id":"1","status":"test status1","updatedAt":"1571145003"},
{"id":"2","status":"test status2","updatedAt":"1571145323"},
{"updatedAt":"1571150000"}
]
_
私は次のような出力が必要です:
_[
{"id":"1","status":"test status1","updatedAt":"1571150000"},
{"id":"2","status":"test status2","updatedAt":"1571150000"}
]
_
私もjsonb_set()
を試しましたが、これには2番目のパラメーターを配列インデックスにする必要があります。配列内のJSONオブジェクトの数がわかりません。
これがカスタム関数で解決できる場合は、これも問題ありません。
最初に配列のすべての要素のネストを解除し、次に各要素を更新してから、単純に配列を構築する元のテーブルを更新します。
with ct as
(
select id, jsonb_array_elements(data) dt
from t
)
, ct2 as
(
select id, jsonb_set(dt, '{updatedAt}', '"1571150000"', false) dt2
from ct
)
update t
set data = (select jsonb_agg(dt2) from ct2 where ct2.id = t.id);
select * from t;
id |データ -:| :------------------------------------------------- -------------------------------------------------- -------------------------------- 1 | [{"id": "1"、 "status": "test status1"、 "updatedAt": "1571150000"}、{"id": "2"、 "status": "test status2"、 "updatedAt": "1571150000"}]
db <> fiddle ここ
McNetsが有効なソリューションを提供したPostgres 10を宣言しました。 CTEはPostgres 12より前にインライン化できないため、CTEを使用しない場合は少し効率的です。
_UPDATE tbl
SET data = (
SELECT jsonb_agg(jsonb_set(d, '{updatedAt}', '"15711500000"', false))
FROM jsonb_array_elements(data) d
);
_
ただし、まだかなり非効率的ですが、実際にはすべて(またはほとんど)の行はneed更新ではありません。すべての行が更新されます-このテストの拡張テストケースで説明したように:
db <>フィドル ここ
すべての行の(小さな)部分だけが実際に更新を必要とする場合、それらのみを更新する方がmuchより効率的です。または、より適切には、それらの行を事前にインデックスサポートで特定します。 Postgres 10では、最初の部分は面倒で、2番目の部分は簡単ではありません(特殊な式のインデックスが必要になります)。
両方とも Postgres 12でSQL/JSONパス言語 :
_UPDATE tbl
SET data = (
SELECT jsonb_agg(jsonb_set(dt, '{updatedAt}', '"15711500000"', false))
FROM jsonb_array_elements(data) dt
)
WHERE data @? '$.updatedAt ? (@ != "1571150000")';
_
追加されたWHERE data @? '$.updatedAt ? (@ != "1571150000")'
は基本的に次のように述べています:
'最上位の(すべての配列要素の) "updatedAt"キーを見て、それらのいずれかが "1571150000"と等しくないかどうかを確認します。そのようなキーが見つかった場合(かつその場合のみ)にtrueを返します。 '
最も重要なのは、これによりUPDATE
から適格でない行が早期に排除されることです。見る:
db <>フィドル ここ
canインデックスも使用します。 マニュアル:
また、GINインデックスは、
jsonpath
マッチングを実行する_@@
_および_@?
_演算子をサポートします。
ただし、_!=
_は_==
_よりもサポートがはるかに難しいため、この特定のケースではインデックスのサポートが制限されています。