何千ものレコードの場合
1。 値$1
で構成される入力行の一時テーブルを作成します 、$2
、$3
。アップロードする最速の方法は、 COPY
です。
-または\copy
psqlのメタコマンド
データが同じマシン上にない場合。このテーブルを想定してみましょう:
CREATE TEMP TABLE tmp(id int PRIMARY KEY, val1 text, val2 text);
完全にオプションのPK制約を追加しましたが、一意のnull以外のint値を処理していることを確認します。入力データを保証できる場合は、制約は必要ありません。
2。 コマンドをデータ変更CTEと連鎖させます。 前の質問 で判断したとおり 、この特定の操作で処理する競合状態はありません。
WITH ins1 AS (
INSERT INTO table1 AS t1 (id, val1, val2)
SELECT id, val1, val2 FROM tmp ON CONFLICT DO NOTHING
RETURNING t1.id, t1.val1, t1.val2 -- only actually inserted rows returned
)
, ins2 AS (
INSERT INTO table2 (table1_id, val1)
SELECT id, val1 FROM ins1
)
UPDATE table3 t3
SET val2 = i.val2
, time = now()
FROM ins1 i
WHERE t3.table1_id = i.id;
手順1と2は、同じセッションで実行する必要があります (必ずしも同じトランザクションである必要はありません)。一時テーブルのスコープは同じセッションにバインドされているためです。
UPDATE
に注意してください 最初のINSERT
にのみ依存します 、2番目のINSERT
の成功 ON CONFLICT DO NOTHING
がないため、保証されます。 2番目のINSERT
で競合が発生した場合、操作全体がロールバックされます。 。
関連:
ほんの数レコード
どのようにさまざまなオプションがあります。 JSON配列を関数に渡すというアイデアはその1つです。オブジェクトがターゲットテーブルと一致する場合は、 json_populate_recordset()
単一のINSERT
クエリ。または、INSERT
を使用します (プリペアドステートメントとして)関数ラッパーなし。
INSERT INTO target_tbl -- it's ok to omit target columns here
SELECT *
FROM json_populate_recordset(null::target_tbl, -- use same table type
json '[{ "id": "1", "val1": "1-val1", "val2": "1-val2" },
{ "id": "2", "val1": "2-val1", "val2": "2-val2" },
{ "id": "3", "val1": "3-val1", "val2": "3-val2" },
{ "id": "4", "val1": "4-val1", "val2": "4-val2" }]');
ほんの一握りの列の場合、各列に配列を渡し、それらを並列にループすることもできます。これは、配列インデックスの単純なループで実行できます。 Postgres 9.4以降、便利なunnest()
もあります。 1つのクエリですべてを実行するための複数のパラメータを使用:
最適なソリューションは、使用しているデータ形式によって異なります 。