web-dev-qa-db-ja.com

PostgresのCSVファイルの値で選択した行を更新する方法は?

私はPostgresを使用していますが、CSVファイルから取得する大きな更新クエリを作成したいと思います。(id, banana, Apple)

リンゴではなくバナナを変更するアップデートを実行したいと思います。新しいバナナとそのIDはそれぞれCSVファイルになります。

Postgresのサイトを見てみましたが、例は私を殺しています。

62
user519753

COPY ファイルを一時的なステージングテーブルに追加し、そこから実際のテーブルを更新します。好む:

CREATE TEMP TABLE tmp_x (id int, Apple text, banana text); -- but see below

COPY tmp_x FROM '/absolute/path/to/file' (FORMAT csv);

UPDATE tbl
SET    banana = tmp_x.banana
FROM   tmp_x
WHERE  tbl.id = tmp_x.id;

DROP TABLE tmp_x; -- else it is dropped at end of session automatically

インポートされたテーブルが更新されるテーブルと正確に一致する場合、これは便利です。

CREATE TEMP TABLE tmp_x AS SELECT * FROM tbl LIMIT 0;

制約なしで、既存のテーブルの構造と一致する空の一時テーブルを作成します。

特典

SQL COPYには、このためのスーパーユーザー権限が必要です。 ( マニュアル ):

COPYファイルまたはコマンドの名前付けは、サーバーがアクセスする権限を持つファイルの読み取りまたは書き込みを許可するため、データベースのスーパーユーザーにのみ許可されます。

psqlメタコマンド\copyはすべてのdbで機能します役割。 マニュアル:

フロントエンド(クライアント)コピーを実行します。これは、SQL COPY コマンドを実行する操作ですが、サーバーが指定したファイルを読み書きする代わりに、psqlはファイルを読み書きし、サーバーとサーバー間でデータをルーティングします。ローカルファイルシステム。これは、ファイルのアクセス可能性と特権がサーバーではなくローカルユーザーのものであり、SQLスーパーユーザー特権が必要ないことを意味します。

一時テーブルのスコープは、単一ロールの単一セッションに制限されているため、上記は同じpsqlセッションで実行する必要があります。

CREATE TEMP TABLE ...;
\copy tmp_x FROM '/absolute/path/to/file' (FORMAT csv);
UPDATE ...;

これをbashコマンドでスクリプト化する場合は、必ずすべてをsinglepsql呼び出しでラップしてください。好む:

echo 'CREATE TEMP TABLE tmp_x ...; \copy tmp_x FROM ...; UPDATE ...;' | psql

通常、メタコマンド\\を使用してpsqlメタコマンドとpsqlのSQLコマンドを切り替える必要がありますが、\copyはこのルールの例外です。再びマニュアル:

\copyメタコマンドには特別な解析ルールが適用されます。他のほとんどのメタコマンドとは異なり、行の残りの部分全体は常に\copyの引数とみなされ、変数の補間や逆引用符の展開は引数で実行されません。

大きなテーブル

インポートテーブルが大きい場合は、セッションの一時的にtemp_buffersを増やすと料金がかかる場合があります(セッションの最初のもの)。

SET temp_buffers = '500MB';  -- example value

一時テーブルにインデックスを追加します。

CREATE INDEX tmp_x_id_idx ON tmp_x(id);

一時テーブルはautovacuum/auto-analyzeでカバーされないため、手動で ANALYZE を実行します。

ANALYZE tmp_x;

関連する回答:

132