(おそらく)PostgreSQL 9.5以降でこれを処理する最良の方法は、INSERT ... ON CONFLICT ... DO UPDATE
です。
のはこれがあなたの元のテーブルであると仮定しましょう(非常に単純には、この例のために):
CREATE TABLE tbl
(
tbl_id INTEGER,
payload JSONB,
CONSTRAINT tbl_pk
PRIMARY KEY (tbl_id)
) ;
我々は始まるデータとそれを埋める:
INSERT INTO tbl
(tbl_id, payload)
VALUES
(1, '{"a":12}'),
(2, '{"a":13, "b": 25}'),
(3, '{"a":15, "b": [12,13,14]}'),
(4, '{"a":12, "c": "something"}'),
(5, '{"a":13, "x": 1234.567}'),
(6, '{"a":12, "x": 1234.789}') ;
今、私たちは非を行います(つまり、ON CONFLICT ... DOは実行されません)。
これで、
:
ON CONFLICT
句によって処理され、今すぐ更新
-- A conflicting insert
INSERT INTO tbl
(tbl_id, payload)
VALUES
(3, '{"a": 16, "b": "I don''t know"}')
ON CONFLICT ON CONSTRAINT tbl_pk DO
UPDATE
SET payload = excluded.payload ;
そして、一列に競合、およびその他を挿入する2つの行挿入を実行するPRIMARY KEY
コンフリクトを生成するNE INSERT
-- Now one of each
-- A conflicting insert
INSERT INTO tbl
(tbl_id, payload)
VALUES
(4, '{"a": 18, "b": "I will we updated"}'),
(9, '{"a": 17, "b": "I am nuber 9"}')
ON CONFLICT ON CONSTRAINT tbl_pk DO UPDATE
SET payload = excluded.payload ;
現在の表をご確認ください:
SELECT * FROM tbl ORDER BY tbl_id ;
tbl_id | payload
-----: | :----------------------------------
1 | {"a": 12}
2 | {"a": 13, "b": 25}
3 | {"a": 16, "b": "I don't know"}
4 | {"a": 18, "b": "I will we updated"}
5 | {"a": 13, "x": 1234.567}
6 | {"a": 12, "x": 1234.789}
7 | {"x": 1234.56, "y": 3456.78}
9 | {"a": 17, "b": "I am nuber 9"}
コードは受信データをループして取得し、INSERT/UPDATE
(時にはMERGE
またはUPSERT
と呼ばれます)を一度に1行ずつ、またはバッチで複数行VALUES
で実行する必要があります。
あなたはhere
dbfiddle ですべてのコードを取得することができますが、バッチで作業する場合より適している一つの代替もあります。あなたはhere dbfiddle で見ることができるようにあなたは、同じ結果が得られます
-- Avoiding (most) concurrency issues.
BEGIN TRANSACTION ;
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE ;
WITH data_to_load (tbl_id, payload) AS
(
VALUES
(3, '{"a": 16, "b": "I don''t know"}' :: jsonb),
(4, '{"a": 18, "b": "I will we updated"}'),
(7, '{"x": 1234.56, "y": 3456.78}'),
(9, '{"a": 17, "b": "I am nuber 9"}')
),
update_existing AS
(
UPDATE
tbl
SET
payload = data_to_load.payload
FROM
data_to_load
WHERE
tbl.tbl_id = data_to_load.tbl_id
)
-- Insert the non-existing
INSERT INTO
tbl
(tbl_id, payload)
SELECT
tbl_id, payload
FROM
data_to_load
WHERE
data_to_load.tbl_id NOT IN (SELECT tbl_id FROM tbl) ;
COMMIT TRANSACTION ;
:INSERT
1に続いて1つのUPDATE
句を、持っているWITH
ステートメントを使用します。どちらの場合も
は、エラー処理のための準備ができて、そしてによる同時アクションに彼ら競合がまたあなたのデータベースを変更する場合は、あなたの取引を再試行して調製すること。は、(第2の場合のように)明示的に指定する、または暗黙のすることができますあなたの取引、あなたは自動コミットのいくつかの種類を持っている場合は、すべて単一INSERT
あなたの実際*質問*は何ですか? – joanolo
私はそれが良いやり方であれば放浪しています –
どのバージョンのPostgreSQLを使用していますか?より新しい(9.5+)バージョンを使用している場合は、おそらく 'INSERT ... ON CONFLICT DO UPDATE ...; 'を使い、すべてを1ステップで実行したいと思うでしょう。 ['INSERT'](https://www.postgresql.org/docs/current/static/sql-insert.html) – joanolo