違いはCSVファイルの場所がサーバかローカルかだけ。
COPY table1 FROM '/path/to/table1.csv' WITH CSV;
\COPY table1 FROM '/path/to/table1.csv' WITH CSV;
COPY table1(id, value) FROM '/path/to/table1.csv' WITH CSV;
\COPY table1(id, value) FROM '/path/to/table1.csv' WITH CSV;
table1に既にデータがあるとき、id重複でエラーになる。
\copy table1(id, value) FROM '/path/to/table1.csv' WITH CSV HEADER;
テーブルを一つ挟むことでupsertに対応する。
table2はtemporaryなので後始末しなくていい。
# table2(一時テーブル、制約なし)作成
CREATE TEMPORARY TABLE table2 AS TABLE table1 WITH NO DATA;
# table2にCSVをインポート
\COPY table2(id, value) FROM '/path/to/table1.csv' WITH CSV HEADER;
# upsert
WITH update_result AS (UPDATE table1 SET id = table2.id, value = table2.value FROM table2 WHERE table1.id = table2.id RETURNING table1.id)
INSERT INTO table1 (id, value) SELECT table2.id, table2.value FROM table2 WHERE table2.id NOT IN (SELECT id FROM update_result);
ただし、大量データだとI/Oが重い。
LIMITつけて間にチェックポイントを挟むとちょっと違う。
table2作成の別解。シーケンスや制約まで複製するとCSVが取り込めない。
CREATE TEMPORARY TABLE table2 (LIKE table1);
# CREATE TEMPORARY TABLE table2 (LIKE table1 INCLUDING DEFAULTS INCLUDING CONSTRAINTS INCLUDING INDEXES);
# CREATE TEMPORARY TABLE table2 (LIKE table1 INCLUDING ALL);
table2からtable1へのupsertの別解。
# table1と紐づくデータをupdate
UPDATE table1
SET id = table2.id, value = table2.value
FROM table2
WHERE table1.id = table2.id;
# updateし終わったtable2の紐付いてるデータを削除
DELETE FROM table2
WHERE id IN (SELECT id FROM table1);
# 残ったtable2のデータをtable1へinsert
INSERT INTO table1 (id, value)
SELECT table2.id, table2.value
FROM table2
WHERE id NOT IN (SELECT id FROM table1);