web-dev-qa-db-ja.com

別のテーブルのすべての列を更新する

テーブルを別のテーブルから更新する必要があり、すべての列を更新する必要があります。 SET句にすべての列をリストする以外に、それらを一度に更新する方法はありますか?このような:

update tableA
set * = tableB.*
from tableB where tableA.id = tableB.id

私はpsqlで試しましたが、うまくいきません。私はこのようにすべての列をリストする必要があります:

update tableA
set c1 = tableB.c1, c2 = tableB.c2, ...
from tableB where tableA.id = tableB.id

tableBcreate .. like tableAを使用して作成されます。したがって、それらは基本的に同じです。そして私がそれをしている理由は、.csvデータを一時テーブルtableBにロードし、tableAの新しいデータに基づいてtableBを更新する必要があるためです。 tableAはできるだけロックしないでください。tableAは整合性を保つ必要があります。 「削除してから挿入」が適切なオプションになるかどうかわかりません。

13
odieatla

no構文バリアントがあり、行全体を一度に更新できます。ただし、これまでの形式より短い形式があります。

また、実際にはすべての列を更新する必要はありません。 idのWHERE条件は、少なくとも1列(id)下がり、変更されません。しかし、それは単なるつまらないことです。

UPDATE table_a a
SET    (  c1,   c2, ...)
     = (b.c1, b.c2, ...)
FROM   table_b b
WHERE  a.id = b.id;

この関連する回答の詳細:
すべての列の一括更新

DELETE / INSERT

内部的には PostgresのMVCCモデル のため、すべてのUPDATEはとにかく新しい行を効果的に挿入し、古い行を古いものとしてマークします。したがって、カーテンの裏側では、UPDATEDELETEINSERTの間に大きな違いはありません。
UPDATEルートを支持するsome詳細があります:

  • ホットアップデート
  • TOASTテーブル:大きな列がある場合、コンテンツはTOASTテーブルに格納される可能性があります。トーストされた列が変更されていない場合、新しい行バージョンはTOASTテーブルの同じ行にリンクできます。
  • インデックスのメンテナンスは、更新の方が安くなる場合があります。

それ以外の場合、ロックはほぼ同じです。影響を受ける行を排他的にロックする必要があります。早くしてください。
非常に多数の行を処理していて、一貫した状態(すべての行またはなし)が必要ない場合は、操作を複数のバッチに分割できます。 (個別のトランザクション!)総コストは増加しますが、行ごとのロック時間は短くなります。

12