160

私は2つのテーブルを持っています:

A [ID, column1, column2, column3]
B [ID, column1, column2, column3, column4]

Aは常に のサブセットになりBます (つまり、 のすべての列はAにも含まれますB)。

のすべての列のデータを使用してID、特定のレコードを更新したいと考えています。これは との両方に存在します。BAAIDAB

「Aのすべての列を設定する」UPDATEと言って、列名を指定せずにそれを行う構文または他の方法はありますか?

私は PostgreSQL を使用しているため、特定の非標準コマンドも受け入れられます (ただし、推奨されません)。

4

7 に答える 7

299

非標準のFROM句を使用できます。

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1
于 2010-05-04T15:41:30.673 に答える
61

質問は古いですが、まだ最良の回答が得られていないと感じました。

列名を指定せずにUPDATE...構文はありますか?

動的 SQL を使用した一般的なソリューション

結合するいくつかの一意の列を除いて、列名を知る必要はありません (id例では)。私が考えることができるあらゆるコーナーケースで確実に機能します。

これは PostgreSQL に固有のものです。私はinformation_schema、特に table に基づいて動的コードを構築していますinformation_schema.columns。これは SQL 標準で定義されており、ほとんどの主要な RDBMS (Oracle を除く) がそれを持っています。しかし、動的 ​​SQL を実行するPL/pgSQLDOコードを含むステートメントは、完全に非標準の PostgreSQL 構文です。

DO
$do$
BEGIN

EXECUTE (
SELECT
  'UPDATE b
   SET   (' || string_agg(        quote_ident(column_name), ',') || ')
       = (' || string_agg('a.' || quote_ident(column_name), ',') || ')
   FROM   a
   WHERE  b.id = 123
   AND    a.id = b.id'
FROM   information_schema.columns
WHERE  table_name   = 'a'       -- table name, case sensitive
AND    table_schema = 'public'  -- schema name, case sensitive
AND    column_name <> 'id'      -- all columns except id
);

END
$do$;

のすべての列bに対して一致する列があると仮定しますが、その逆ではありません。追加の列を持つことができます。ab

WHERE b.id = 123選択した行を更新するためのオプションです。

ここでdb<>fiddle
古いsqlfiddle

関連する回答と詳細な説明:

プレーン SQL による部分的なソリューション

共有列のリストあり

両方のテーブルが共有する列名のリストを知る必要があります。複数の列を更新するための構文ショートカットを使用すると、これまでに提案された他の回答よりも短くなります。

UPDATE b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   a
WHERE  b.id = 123    -- optional, to update only selected row
AND    a.id = b.id;

ここでdb<>fiddle
古いsqlfiddle

この構文は、質問がされるずっと前の 2006 年に Postgres 8.2 で導入されました。詳細はマニュアルにて。

関連している:

列のリストを含むB

のすべての列Aが定義されておりNOT NULL(必ずしもであるBは限りません)、の列名がわかっている場合(必ずしも であるとは限りません)。
BA

UPDATE b
SET   (column1, column2, column3, column4)
    = (COALESCE(ab.column1, b.column1)
     , COALESCE(ab.column2, b.column2)
     , COALESCE(ab.column3, b.column3)
     , COALESCE(ab.column4, b.column4)
      )
FROM (
   SELECT *
   FROM   a
   NATURAL LEFT JOIN  b -- append missing columns
   WHERE  b.id IS NULL  -- only if anything actually changes
   AND    a.id = 123    -- optional, to update only selected row
   ) ab
WHERE b.id = ab.id;

は、同じ名前のすべての列が同じ値を保持NATURAL LEFT JOINする行を結合します。bこの場合、更新は必要なく (何も変更されない)、プロセスの早い段階でこれらの行を削除できます ( WHERE b.id IS NULL)。
一致する行をまだ見つける必要があるためb.id = ab.id、外側のクエリで.

ここでdb<>fiddle
古いsqlfiddle

これは、句を除いてFROM標準 SQLです。
に実際に存在する列に関係なく動作Aしますが、クエリは実際の NULL 値と にない列を区別できないため、 のすべての列が定義されているA場合にのみ信頼できます。ANOT NULL

両方のテーブルについて知っていることに応じて、複数のバリエーションが考えられます。

于 2014-04-25T03:46:18.517 に答える
6

必ずしもあなたが尋ねたものではありませんが、postgres継承を使用すると役立つかもしれませんか?

CREATE TABLE A (
    ID            int,
    column1       text,
    column2       text,
    column3       text
);

CREATE TABLE B (
    column4       text
) INHERITS (A);

これにより、B を更新する必要がなくなります。

ただし、すべての詳細を必ずお読みください。

それ以外の場合、あなたが求めることは良い習慣とは見なされません - ビューのような動的なものSELECT * ...はお勧めできません (そのようなわずかな便利さは、ヘルプよりも多くのものを壊す可能性があるため)、あなたが求めるものはUPDATE ... SETコマンドと同等です。

于 2010-05-04T08:48:10.177 に答える
1

これを行うために動的SQLを構築して実行できますが、実際には理想的ではありません

于 2010-05-04T08:29:43.160 に答える
-4

フォローしてみる

Update A a, B b, SET a.column1=b.column1 where b.id=1

編集済み:- 複数の列を更新する

Update A a, B b, SET a.column1=b.column1, a.column2=b.column2 where b.id=1
于 2010-05-04T08:33:07.613 に答える