SQLは、あるテーブルのフィールドを別のテーブルのフィールドから更新します


124

2つのテーブルがあります。

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

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

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

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

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


これはあなたがやりたいことだと思います、dba.stackexchange.com
a /

回答:


234

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

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1

9
問題は、すべての列名指定せずにそれを行う方法についてです。(そして私もそうです。)
2012

2
@cluesqueに同意しますが、この回答は、テーブルの1つの列の値を別のテーブルの列の値を置き換えるためのルックアップテーブルとして使用するための優れた方法です(SO 21657475を参照)。したがって、+ 1 ...
Victoria Stuart

1
なぜb.id = 1が必要なのですか?
YasirAzgar

1
@YasirAzgar b.id = 1は、bのどの行が更新されるかを制限することです。それ以外の場合は、テーブルのすべての行を更新します。時々、それがあなたの望むものかもしれません。しかし、元の質問はbの特定の行を更新することでした。
スコットベイリー

これは、私の特定の問題に必要なものです。あるテーブルの列を、別のテーブルの別の名前の列の値で更新します。
muad-dweeb

49

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

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

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

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

これはPostgreSQLに固有です。information_schemaに基づいて動的コードを構築しています。特にinformation_schema.columns、SQL標準で定義されているtable であり、ほとんどの主要なRDBMS(Oracleを除く)がそれを持っています。しかし、動的SQLを実行するPL / pgSQLコードDOを含むステートメントは、完全に非標準の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 選択した行を更新するためのオプションです。

SQL Fiddle。

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

プレーン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;

SQL Fiddle。

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

関連:

の列のリスト B

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

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 here
Old sqlfiddle。

これはFROM句を除いて標準SQL です。
どの列が実際に存在してAいても機能しますが、クエリは実際のNULL値と欠落している列を区別できないためA、すべての列Aが定義されている場合にのみ信頼できますNOT NULL

両方のテーブルについての知識に応じて、複数の可能なバリエーションがあります。


SQLの力!あなたはset句(中括弧を追加するときだけに気づいSET (column1) = (a.column):Postgresは、更新の別の種類として扱い、次のように与えるとエラーになる)source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression
エドガー・オルテガ

26

私はIBM DB2データベースを10年以上使用しており、現在はPostgreSQLを学習しようとしています。

PostgreSQL 9.3.4では機能しますが、DB2 10.5では機能しません。

UPDATE B SET
     COLUMN1 = A.COLUMN1,
     COLUMN2 = A.COLUMN2,
     COLUMN3 = A.COLUMN3
FROM A
WHERE A.ID = B.ID

注:主な問題は、DB2でもANSI SQLでもサポートされていないFROM原因です。

DB2 10.5では機能しますが、PostgreSQL 9.3.4では機能しません。

UPDATE B SET
    (COLUMN1, COLUMN2, COLUMN3) =
               (SELECT COLUMN1, COLUMN2, COLUMN3 FROM A WHERE ID = B.ID)

最後に!PostgreSQL 9.3.4とDB2 10.5の両方で動作します。

UPDATE B SET
     COLUMN1 = (SELECT COLUMN1 FROM A WHERE ID = B.ID),
     COLUMN2 = (SELECT COLUMN2 FROM A WHERE ID = B.ID),
     COLUMN3 = (SELECT COLUMN3 FROM A WHERE ID = B.ID)

3
2番目と3番目のクエリは、最初のクエリと完全に同等ではないことに注意してください。で一致する行が見つからない場合B、最初のステートメントは何も(元の行はそのままです)、他の2つの列はNULL値で列を上書きします。
Erwin Brandstetter 2014

7

これは非常に役立ちます。コード

UPDATE tbl_b b
SET   (  column1,   column2,   column3)
    = (a.column1, a.column2, a.column3)
FROM   tbl_a a
WHERE  b.id = 1
AND    a.id = b.id;

完璧に動作します。

で括弧「」が必要であることに注意してください

From "tbl_a" a

それを動作させるために。


5

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

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

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

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

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

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


継承がこれをどのように解決するかわかりません。Aの更新トリガーを追加して、Bも更新するということですか?リクエストがあった場合にのみ、Aを常にBと同期させたくありません。そのような場合、トリガーを使用できません。
Nir

2
はい、それが特定の場合にのみある場合、継承は機能しません。その場合は、動的クエリアプローチを使用しないことをお勧めします。(まだpostgres手続き言語を使用してこれを達成する方法があります。トリガーを使用したい場合は、それらも使用できます-たとえば、設定されている場合にのみトリガーを起動するなどの同期フィールドを追加します)。
Unreason

0

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


私はそれについて考えました。クエリを両方のテーブルに対する後の変更に準拠させることができると思いましたが、動的SQLはすべてのフィールドを指定して前方互換性を忘れるほど複雑すぎるようです。
2010年

はい、複雑になりますが、追加または削除される後の列との上位互換性があります。最初にクエリを実行して両方のテーブルから列名を取得し、次に列名を一致させてから、動的SQLを記述して、一致する列名に基づいて更新を行う必要があります。実際に楽しいプロジェクト:)
Daniel Brink

-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

column1、column2、column3をコピーする方法がわかりません。そして、私は明示的に言及する必要がありますcolumn1。
Nir

私にはうまくいきません。次のエラーが表示されます:エラー: "、"またはその近くの構文エラー
メルビック

1
この非標準の構文はUPDATEMySQLでは機能しますが、PostgreSQLでは無効です。
Erwin Brandstetter 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.