Bir tablonun diğerinin alanlarından SQL güncelleme alanları


124

İki masam var:

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

Aher zaman alt kümesi olacaktır B(yani tüm sütunları Ada içindedir B).

Tüm sütunlar için verileriyle belirli bir IDgirişi Bolan bir kaydı güncellemek istiyorum . Bu hem mevcut ve .AAIDAB

UPDATESütun adlarını belirtmeden, sadece "A'nın tüm sütunlarını ayarla" diyerek bunu yapmanın bir sözdizimi veya başka bir yolu var mı?

PostgreSQL kullanıyorum, bu nedenle standart olmayan belirli bir komut da kabul edilir (ancak tercih edilmez).


Sanırım yapmak istediğin bu, dba.stackexchange.com/a/58383
zubair-0

Yanıtlar:


235

Standart olmayan FROM yan tümcesini kullanabilirsiniz.

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

9
Soru bunu nasıl olduğumu soruyor olmadan tüm sütun adlarını belirterek. (Ve ben de öyleyim.)
ipucu

2
@Cluesque'e katılıyorum, ancak bu yanıt, bir tablodaki bir sütundaki değerleri başka bir tablodaki bir sütundaki değerleri değiştirmek için bir arama tablosu olarak kullanmanın mükemmel bir yoludur (bkz. SO 21657475 ), yani +1 ...
Victoria Stuart

1
Neden b.id = 1 gereklidir?
YasirAzgar

1
@YasirAzgar b.id = 1, b'deki hangi satırların güncelleneceğini sınırlamaktır. Aksi takdirde tablodaki her satırı güncellerdik. Bazen istediğin bu olabilir. Ancak asıl soru, b'deki belirli bir satırı güncellemekti.
Scott Bailey

Sorunum için ihtiyacım olan şey bu: bir tablonun sütununu başka bir tablonun farklı adlandırılmış sütunundaki değerlerle güncellemek.
muad-dweeb

49

Soru eski ama en iyi cevabın henüz verilmediğini hissettim.

Bir ... var mı UPDATESütun adlarını belirtmeden ... sözdizimi ?

Dinamik SQL ile genel çözüm

Katılmak için bazı benzersiz sütunlar dışında herhangi bir sütun adı bilmenize gerek yoktur (id örnekte). Aklıma gelen herhangi bir olası köşe durumunda güvenilir bir şekilde çalışıyor.

Bu, PostgreSQL'e özgüdür. Bilgi şemasına information_schema.columns, özellikle SQL standardında tanımlanan ve en büyük RDBMS'de (Oracle hariç) buna sahip olan tabloya dayalı dinamik kod oluşturuyorum . Ancak dinamik SQL çalıştıran PL / pgSQL kodlu bir DOifade , tamamen standart olmayan PostgreSQL sözdizimidir.

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

Her sütun biçin eşleşen bir sütun varsayarsak , ancak tersi olmaz. ek sütunlar olabilir.ab

WHERE b.id = 123 seçili bir satırı güncellemek için isteğe bağlıdır.

SQL Fiddle.

Daha fazla açıklamayla ilgili yanıtlar:

Düz SQL ile kısmi çözümler

Paylaşılan sütunların listesiyle

Yine de her iki tablonun paylaştığı sütun adlarının listesini bilmeniz gerekir. Birden çok sütunu güncellemek için bir sözdizimi kısayolu ile - her durumda şimdiye kadar önerilen diğer yanıtlardan daha kısadır.

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.

Bu sözdizimi, soru sorulmadan çok önce, 2006 yılında Postgres 8.2 ile tanıtıldı. Kılavuzdaki ayrıntılar.

İlişkili:

İçindeki sütunların listesi ile B

Eğer tüm sütunlar Atanımlanmıştır NOT NULL(şart olmamakla birlikte B),
ve sen biliyorsun sütun isimlerini B(şart olmamakla birlikte 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 JOINBir satırı katılır baynı adı taşıyan tüm sütunlar aynı değerleri barındırdığı yerde. Bu durumda bir güncellemeye ihtiyacımız yoktur (hiçbir şey değişmez) ve bu satırları sürecin başlarında ortadan kaldırabiliriz ( WHERE b.id IS NULL).
Hala eşleşen bir satır bulmamız gerekiyor.b.id = ab.idDış sorguda .

db <> fiddle here
Eski sqlfiddle.

Bu, yan tümce hariçFROM standart SQL'dir .
Hangi sütunlarda gerçekten mevcut olursa olsun çalışır A, ancak sorgu gerçek NULL değerleri ile eksik sütunları birbirinden ayırt edemez A, bu nedenle yalnızca içindeki tüm sütunlarA tanımlanmışsaNOT NULL .

Her iki tablo hakkında bildiklerinize bağlı olarak birden fazla olası varyasyon vardır .


SQL'in gücü! Set cümlesine ( SET (column1) = (a.column)) parantez eklediğinizde fark ettim ki, Postgres bunu başka bir güncelleme türü olarak ele alacak ve şu şekilde source for a multiple-column UPDATE item must be a sub-SELECT or ROW() expression
Edgar Ortega

26

On yıldan fazla bir süredir IBM DB2 veritabanı ile çalışıyorum ve şimdi PostgreSQL öğrenmeye çalışıyorum.

PostgreSQL 9.3.4 üzerinde çalışır, ancak DB2 10.5 üzerinde çalışmaz:

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

Not: Ana sorun, DB2'de ve ANSI SQL'de desteklenmeyen NEDEN nedenidir.

DB2 10.5 üzerinde çalışır, ancak PostgreSQL 9.3.4 üzerinde ÇALIŞMAZ:

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

EN SONUNDA! Hem PostgreSQL 9.3.4 hem de DB2 10.5'te çalışır:

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
İkinci ve üçüncü sorguların birincisine tamamen eşdeğer olmadığını unutmayın. İçinde eşleşen bir satır bulunmazsa B, ilk ifade hiçbir şey yapmaz (orijinal satır dokunulmadan kalır), diğer iki sütun NULL değerlerle sütunların üzerine yazar.
Erwin Brandstetter

7

Bu harika bir yardım. Kod

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;

Mükemmel çalışıyor.

içinde bir köşeli paranteze "" ihtiyacınız olduğunu kaydetti

From "tbl_a" a

çalışmasını sağlamak için.


5

İstediğiniz her zaman değil, ancak postgres kalıtımını kullanmak yardımcı olabilir mi?

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

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

Bu, B'yi güncelleme ihtiyacını ortadan kaldırır.

Ancak tüm detayları okuduğunuzdan emin olun .

Aksi takdirde, istediğiniz şey iyi bir uygulama olarak kabul edilmez - görüşler gibi dinamik şeyler SELECT * ...cesaret kırılır (çünkü bu tür hafif bir kolaylık yardım şeylerinden daha fazla şeyi bozabilir) ve istediğiniz şey UPDATE ... SETkomuta eşdeğer olacaktır .


Mirasın bunu nasıl çözeceğinden emin değilim. A için B'yi de güncelleyen bir güncelleme tetikleyicisi eklemeyi mi kastediyorsunuz? A'yı her zaman B ile senkronize etmek istemiyorum, sadece istek üzerine. Ve böyle bir durumda, tetikleyicileri kullanamam.
Nir

2
Evet, eğer sadece belirli durumlarda ise, kalıtım çalışmayacaktır ve bu durumda dinamik sorgu yaklaşımına karşı tavsiye ederim. (yine de postgres prosedürel dilleri kullanarak bunu başarmanın yolları vardır. ayrıca tetikleyicileri kullanmak istiyorsanız, bunları da kullanabilirsiniz - örneğin, yalnızca ayarlandığında tetikleme tetikleme gibi senkronizasyon alanı ekleyerek).
mantıksızlık

0

Bunu yapmak için dinamik sql oluşturabilir ve yürütebilirsiniz, ancak bu gerçekten ideal değil


Bunu düşündüm. Sorgumu her iki tablodaki daha sonraki değişikliklerle uyumlu hale getirebileceğimi düşündüm, ancak dinamik sql, tüm alanları belirtmekten ve ileriye dönük uyumluluğu unutmaktan çok karmaşık görünüyor.
Nir

evet, karmaşık olacaktır, ancak daha sonra eklenen veya kaldırılan sütunlar ile ileriye dönük uyumlu olmalıdır. Her iki tablodan da sütun adlarını almak için önce bir sorgu yapmanız, ardından sütun adlarını eşleştirmeniz ve ardından eşleşen sütun adlarına göre güncellemeyi yapmak için dinamik sql yazmanız gerekir. aslında eğlenceli bir proje :)
Daniel Brink

-4

İzlemeyi Deneyin

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

DÜZENLENDİ: - Birden fazla sütunu güncelleyin

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

Sütun1, sütun2 ve sütun3'ü nasıl kopyaladığını anlamıyorum. Ve 1. sütunu açıkça belirtmem gerekiyor.
Nir

Benim için çalışmıyor. Şu hatayı alıyorum: HATA: "," konumunda veya yakınında sözdizimi hatası
melbic

1
Bu standart olmayan sözdizimi MySQL'de işe UPDATEyarar , ancak PostgreSQL için geçersizdir.
Erwin Brandstetter
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.