Bidang pembaruan SQL dari satu tabel dari bidang yang lain

124

Saya memiliki dua tabel:

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

Aakan selalu menjadi bagian dari B(artinya semua kolom Ajuga dalam B).

Saya ingin memperbarui catatan dengan spesifik IDdalam Bdengan datanya dari Auntuk semua kolom A. Ini IDada di Adan B.

Apakah ada UPDATEsintaks atau cara lain untuk melakukannya tanpa menentukan nama kolom, hanya mengatakan "setel semua kolom A" ?

Saya menggunakan PostgreSQL, jadi perintah non-standar tertentu juga diterima (namun, tidak disukai).

Nir
sumber
Saya pikir inilah yang ingin Anda lakukan, dba.stackexchange.com/a/58383
-0

Jawaban:

234

Anda dapat menggunakan klausa FROM non-standar .

UPDATE b
SET column1 = a.column1,
  column2 = a.column2,
  column3 = a.column3
FROM a
WHERE a.id = b.id
AND b.id = 1
Scott Bailey
sumber
9
Pertanyaannya adalah menanyakan tentang bagaimana melakukannya tanpa menentukan semua nama kolom. (Dan aku juga.)
petunjuk
2
Saya setuju dengan @cluesque, tetapi jawaban ini adalah cara terbaik untuk menggunakan nilai dalam satu kolom dalam tabel sebagai tabel pencarian untuk mengganti nilai dalam kolom di tabel lain (lihat SO 21657475 ), jadi +1 ...
Victoria Stuart
1
Mengapa b.id = 1 dibutuhkan?
YasirAzgar
1
@YasirAzgar the b.id = 1 adalah untuk membatasi baris apa di b yang diperbarui. Jika tidak, kami akan memperbarui setiap baris dalam tabel. Terkadang, itu mungkin yang Anda inginkan. Tetapi pertanyaan awal adalah memperbarui baris tertentu di b.
Scott Bailey
Inilah yang saya butuhkan untuk masalah khusus saya: memperbarui satu kolom tabel dengan nilai dari kolom tabel lain dengan nama berbeda.
muad-dweeb
49

Pertanyaannya sudah lama tetapi saya merasa jawaban terbaik belum diberikan.

Apakah ada UPDATEsintaks ... tanpa menentukan nama kolom ?

Solusi umum dengan SQL dinamis

Anda tidak perlu mengetahui nama kolom apa pun kecuali beberapa kolom unik untuk digabungkan ( iddalam contoh). Bekerja dengan andal untuk setiap kemungkinan kasus sudut yang dapat saya pikirkan.

Ini khusus untuk PostgreSQL. Saya membangun kode dinamis berdasarkan information_schema , khususnya tabel information_schema.columns, yang didefinisikan dalam standar SQL dan sebagian besar RDBMS (kecuali Oracle) memilikinya. Tetapi DOpernyataan dengan kode PL / pgSQL yang menjalankan SQL dinamis benar-benar sintaks PostgreSQL non-standar.

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$;

Mengasumsikan kolom yang cocok buntuk setiap kolom masuk a, tetapi tidak sebaliknya. bdapat memiliki kolom tambahan.

WHERE b.id = 123 bersifat opsional, untuk memperbarui baris yang dipilih.

SQL Fiddle.

Jawaban terkait dengan penjelasan lebih lanjut:

Solusi parsial dengan SQL biasa

Dengan daftar kolom bersama

Anda tetap perlu mengetahui daftar nama kolom yang dimiliki kedua tabel tersebut. Dengan pintasan sintaks untuk memperbarui beberapa kolom - lebih pendek dari jawaban lain yang disarankan sejauh ini.

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.

Sintaks ini diperkenalkan dengan Postgres 8.2 pada tahun 2006, jauh sebelum pertanyaan diajukan. Detail di manual.

Terkait:

Dengan daftar kolom dalam B

Jika semua kolom Aditentukan NOT NULL(tetapi tidak harus B),
dan Anda tahu nama kolomnya B(tetapi tidak harus 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;

The NATURAL LEFT JOINbergabung berturut-turut dari bmana semua kolom dengan nama yang sama memegang nilai-nilai yang sama. Kami tidak memerlukan pembaruan dalam kasus ini (tidak ada yang berubah) dan dapat menghilangkan baris tersebut di awal proses ( WHERE b.id IS NULL).
Kami masih perlu menemukan baris yang cocok, jadi b.id = ab.iddi kueri luar.

db <> biola di sini Sqlfiddle
tua .

Ini adalah SQL standar kecuali untuk FROMklausa .
Ini berfungsi tidak peduli di kolom mana sebenarnya ada A, tetapi kueri tidak dapat membedakan antara nilai NULL aktual dan kolom yang hilang A, jadi hanya dapat diandalkan jika semua kolom di Aditentukan NOT NULL.

Ada beberapa kemungkinan variasi, bergantung pada apa yang Anda ketahui tentang kedua tabel.

Erwin Brandstetter
sumber
Kekuatan SQL! Baru saja diperhatikan ketika Anda menambahkan tanda kurung di klausa set ( SET (column1) = (a.column)) Postgres akan memperlakukannya sebagai jenis pembaruan lain dan memberi dan kesalahan seperti ini:source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression
Edgar Ortega
26

Saya telah bekerja dengan database IBM DB2 selama lebih dari satu dekade dan sekarang mencoba mempelajari PostgreSQL.

Ini berfungsi pada PostgreSQL 9.3.4, tetapi tidak berfungsi pada DB2 10.5:

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

Catatan: Masalah utama adalah DARI penyebab yang tidak didukung di DB2 dan juga tidak di ANSI SQL.

Ini berfungsi pada DB2 10.5, tetapi TIDAK berfungsi pada PostgreSQL 9.3.4:

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

AKHIRNYA! Ini berfungsi pada PostgreSQL 9.3.4 dan 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)
jochan
sumber
3
Perhatikan bahwa kueri kedua dan ketiga tidak sepenuhnya sama dengan yang pertama. Jika tidak ada baris yang cocok ditemukan B, pernyataan pertama tidak melakukan apa - apa (baris asli tetap tidak tersentuh), sedangkan dua lainnya menimpa kolom dengan nilai NULL.
Erwin Brandstetter
7

Ini sangat membantu. Kode

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;

bekerja dengan sempurna.

mencatat bahwa Anda memerlukan tanda kurung "" di

From "tbl_a" a

untuk membuatnya berhasil.

pengguna2493970
sumber
5

Belum tentu apa yang Anda tanyakan, tetapi mungkin menggunakan warisan postgres dapat membantu?

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

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

Ini menghindari kebutuhan untuk memperbarui B.

Tapi pastikan untuk membaca semua detailnya .

Jika tidak, apa yang Anda minta tidak dianggap sebagai praktik yang baik - hal-hal dinamis seperti pandangan dengan SELECT * ...tidak disarankan (karena sedikit kemudahan dapat merusak lebih banyak hal daripada hal bantuan), dan apa yang Anda minta akan setara dengan UPDATE ... SETperintah.

Tidak masuk akal
sumber
Saya tidak yakin bagaimana warisan akan menyelesaikan masalah ini. Apakah maksud Anda menambahkan pemicu pembaruan untuk A yang juga memperbarui B? Saya tidak ingin menyinkronkan A dengan B sepanjang waktu, hanya jika diminta. Dan dalam kasus seperti itu, saya tidak dapat menggunakan pemicunya.
Nir
2
Ya, jika hanya dalam kasus tertentu maka warisan tidak akan berfungsi dan dalam kasus itu saya menyarankan agar pendekatan kueri dinamis. (masih ada cara untuk mencapai ini menggunakan bahasa prosedural postgres. juga jika Anda ingin menggunakan pemicu, Anda dapat menggunakannya juga - dengan menambahkan bidang sinkronisasi misalnya mengaktifkan pemicu hanya jika disetel).
Unreason
0

Anda dapat membangun dan menjalankan sql dinamis untuk melakukan ini, tetapi sebenarnya ini tidak ideal

Daniel Brink
sumber
Saya memikirkan tentang itu. Saya pikir saya bisa membuat kueri saya sesuai dengan perubahan selanjutnya pada kedua tabel, tetapi sql dinamis tampaknya terlalu rumit daripada hanya menentukan semua bidang dan melupakan kompatibilitas ke depan.
Nir
ya, ini akan menjadi rumit, tetapi harus kompatibel dengan kolom selanjutnya yang ditambahkan atau dihapus. Anda harus terlebih dahulu melakukan kueri untuk mendapatkan nama kolom dari kedua tabel, lalu mencocokkan nama kolom dan kemudian menulis sql dinamis untuk melakukan pembaruan berdasarkan nama kolom yang cocok. sebuah proyek yang menyenangkan sebenarnya :)
Daniel Brink
-4

Coba Ikuti

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

DIEDIT: - Perbarui lebih dari satu kolom

Update A a, B b, SET a.column1=b.column1, a.column2=b.column2 where b.id=1
Salil
sumber
Saya tidak mengerti cara menyalin kolom1, kolom2, dan kolom3. Dan saya perlu menyebutkan kolom1 secara eksplisit.
Nir
Tidak berhasil untuk saya. Saya mendapatkan kesalahan berikut: ERROR: kesalahan sintaks pada atau dekat ","
melbic
1
Sintaks non-standar ini akan berfungsi UPDATEdi MySQL , tetapi tidak valid untuk PostgreSQL.
Erwin Brandstetter