Oracle SQL: Bir tabloyu başka bir tablodaki verilerle güncelleme


251

Tablo 1:

id    name    desc
-----------------------
1     a       abc
2     b       def
3     c       adf

Tablo 2:

id    name    desc
-----------------------
1     x       123
2     y       345

Oracle SQL, nasıl bir çalıştırırım sql güncelleme Tablo 2 yıllardan ile Tablo 1 güncelleyebilir sorgu nameve descaynı kullanarak id? Sonuçta alacağım sonuç

Tablo 1:

id    name    desc
-----------------------
1     x       123
2     y       345
3     c       adf

Soru, bir tabloyu diğerinden verilerle güncellemek , ancak özellikle oracle SQL için alınır.



Diğer sorunuza geri dönmeniz, bu yanıtı kabul etmemeniz ve özellikle Oracle PLSQL sözdizimine ihtiyacınız olduğunu belirtmeniz gerekir.
p.campbell

3
@ p.campbell, Bu benim sorum değil ...
Muhd

1
Ah anlıyorum. Böylece soru gövdesini kopyaladınız, ancak Oracle bitini içerecek şekilde değiştirdiniz.
p.campbell

2
Evet. Ve bu muhtemelen en iyi örnek değildir çünkü "desc" ayrılmış bir sözcüktür, ama iyi.
Muhd

Yanıtlar:


512

Buna ilişkili güncelleme denir

UPDATE table1 t1
   SET (name, desc) = (SELECT t2.name, t2.desc
                         FROM table2 t2
                        WHERE t1.id = t2.id)
 WHERE EXISTS (
    SELECT 1
      FROM table2 t2
     WHERE t1.id = t2.id )

Birleştirme sonuçlarını anahtarla korunan bir görünümde kabul ettiğinizde,

UPDATE (SELECT t1.id, 
               t1.name name1,
               t1.desc desc1,
               t2.name name2,
               t2.desc desc2
          FROM table1 t1,
               table2 t2
         WHERE t1.id = t2.id)
   SET name1 = name2,
       desc1 = desc2

8
İlk kod örneğinizde: Dış WHERE yan tümcesi doğru sonuçlar için gerekli mi? Yoksa yalnızca sorguyu hızlandırmak için mi kullanıyorsunuz?
Mathias Bader

41
@totoro - İlk örnekte, eşleşen WHERE EXISTSbir satır t1yoksa bir satırı güncellemenizi engeller t2. Bu olmadan, içindeki her satır t1güncellenecek ve NULLeşleşen bir satır yoksa değerler olarak ayarlanacaktır t2. Genelde olmasını istediğiniz şey bu değildir, bu yüzden WHERE EXISTSgenellikle gereklidir.
Justin Cave

3
Eşsiz bir satırla sonuçlanması SELECT ... FROM t2 gerektiğini eklemeye değer . Bu, benzersiz bir anahtar içeren tüm alanları seçmeniz gerektiği anlamına gelir - benzersiz olmayan bir birincil anahtar yeterli değildir. Benzersizlik olmadan, @ PaulKarr'ın döngüsü gibi bir şeye indirgenirsiniz - ve benzersiz bir korelasyon yoksa, her kaynak satırı için birden fazla hedef satır güncellenebilir.
Andrew Leach


1
@RachitSharma - Bu, alt sorgunuzun (sorgu kaynağı table2) bir veya daha fazla table1değer için birden çok satır döndürdüğü ve Oracle'ın hangisini kullanmak istediğinizi bilmediği anlamına gelir. Normalde bu, alt sorguyu tek bir ayrı satır döndürecek şekilde hassaslaştırmanız gerektiği anlamına gelir.
Justin Cave

133

Bunu dene:

MERGE INTO table1 t1
USING
(
-- For more complicated queries you can use WITH clause here
SELECT * FROM table2
)t2
ON(t1.id = t2.id)
WHEN MATCHED THEN UPDATE SET
t1.name = t2.name,
t1.desc = t2.desc;

4
Çok hızlı, 1159477 satır 15,5'lerde birleşti
jefissu

4
Umarım 2015'ten sonra bu soruyu ziyaret eden herkes bu cevabı fark eder. Not Bu da eğer çalıştığını table1ve table2aynı tablo vardır, sadece özen ON-bölümüne ve WHEREiçin -clause SELECTait -Bildirim table2!
sjngm

1
Başka bir birleştirme yapmam gerektiğinde ilham için bu cevaba geri dönmeye devam ettiğimi görüyorum. Onu basabilir ve
duvarımda

Çekicilik gibi çalışır !! Teşekkürler!
davidwillianx

Tablo2'den DISTINCT ID, FIELD1, FIELD1 SEÇİN NERİ KİMLİK NULL DEĞİL
Joseph Poirier

17

Deneyin

UPDATE Table1 T1 SET
T1.name = (SELECT T2.name FROM Table2 T2 WHERE T2.id = T1.id),
T1.desc = (SELECT T2.desc FROM Table2 T2 WHERE T2.id = T1.id)
WHERE T1.id IN (SELECT T2.id FROM Table2 T2 WHERE T2.id = T1.id);

4
Bunun dezavantajı, SELECT ifadesinin 3 kez tekrarlanmasıdır. Karmaşık örneklerde bir anlaşma kırıcı olabilir.
David Balažic

9
Update table set column = (select...)

set yalnızca 1 değer beklediğinden benim için hiç çalışmadı - SQL Hatası: ORA-01427: tek satırlı alt sorgu birden fazla satır döndürüyor.

İşte çözüm:

BEGIN
For i in (select id, name, desc from table1) 
LOOP
Update table2 set name = i.name, desc = i.desc where id = i.id;
END LOOP;
END;

SQLDeveloper çalışma sayfasında tam olarak bu şekilde çalıştırırsınız. Yavaş diyorlar ama bu davada benim için çalışan tek çözüm bu.


Birisi bunun neden itibar konusunda -2'yi hak ettiğini açıklayabilir mi? LOL.
Pau Karr

13
Oranı aşağı vermedi, ama iyi bir çözüm değil. İlk olarak: alt seçim birden fazla değer döndürüyorsa, for döngüsü bazı / tüm kayıtlar için (temiz değil) tablo2'deki adın üzerine birden çok kez yazacaktır. İkincisi: maddeye göre bir düzen yoktur, bu nedenle bu tahmin edilemez bir şekilde gerçekleşir (yani sıralanmamış verilerdeki son değer kazanır). Üçüncüsü: Çok daha yavaş olacaktır. Düşünülmüştü için döngü sonucunu varsayarsak, orijinal alt seçim her kayıt için sadece 1 değer döndürmek için bazı kontrollü bir şekilde yeniden yazılmış olabilirdi ... en basit yapmacık yolu (...) min (isim seç) olurdu
Alternatör

Tam da ihtiyacım olan buydu. Teşekkürler (+1)
Robert Hyatt

3
Alt sorgunuzda birden çok değer alırsanız, sorguyu yeniden düşünebilir ve DISTINCT veya GROUP BY işlevini MIN, MAX ile kullanabilirsiniz. Sadece bir fikir.
Francis

Uzun lafın kısası: Eğer bundan kaçınabiliyorsanız, asla bir T-SQL deyiminde herhangi bir LOOP kullanmayın. Şahsen, başka bir çözümün olmadığı zamanın% 0.001'i olmasaydı, T-SQL'de kullanılabilir bir işlev olması gerektiğini bile düşünmüyorum. T-SQL set tabanlı olacak şekilde tasarlanmıştır, bu nedenle bir bütün olarak tüm veri setlerinde çalışır; veri üzerinde satır satır çalışmak için KULLANILMAMALIDIR.
Ray K.

8

İşte katılmak için birden fazla anahtar sağlayan 'in' yan tümcesinde daha iyi bir yanıt gibi görünüyor :

update fp_active set STATE='E', 
   LAST_DATE_MAJ = sysdate where (client,code) in (select (client,code) from fp_detail
  where valid = 1) ...

Sığır eti, önce 'in' deyiminde parantez içinde anahtar olarak kullanmak istediğiniz sütunlara sahip ve parantez içinde aynı sütun adlarına sahip select deyimine sahip. nerede ( sütun1, sütun2 olarak) ( seçmek ( sütun1, sütun2 tablosundan) burada "seti istediğim" );


Bağlantının süresi doldu. ( 404)
Dumbo

-3

Tablonuz t1 ve yedek t2'sinde çok sayıda sütun varsa, bunu yapmanın kompakt bir yolu var.

Buna ek olarak, ilgili sorunum sadece bazı sütunların değiştirilmiş olması ve birçok satırın bu sütunlarda hiçbir düzenlemesi olmamasıydı, bu yüzden bunları yalnız bırakmak istedim - temelde tüm tablonun yedeğinden bir sütun alt kümesini geri yüklemek istedim. Tüm satırları geri yüklemek istiyorsanız where yan tümcesini atlayın.

Tabii ki daha basit yol silmek ve seçmek gibi eklemek olacaktır, ama benim durumumda sadece güncellemeleri olan bir çözüme ihtiyacım vardı.

İşin püf noktası, yinelenen sütun adlarına sahip bir çift tablodan * seçtiğinizde, ikincisi _1 olarak adlandırılacaktır. İşte ben geldim:

  update (
    select * from t1 join t2 on t2.id = t1.id
    where id in (
      select id from (
        select id, col1, col2, ... from t2
        minus select id, col1, col2, ... from t1
      )
    )
  ) set col1=col1_1, col2=col2_1, ...

Oracle 11g'de bu benim için çalışmıyor. Bu yöntemin çalışan bir örneğini oluşturabilir misiniz?
Jon Heller

-3
BEGIN
For i in (select id, name, desc from table2) 
LOOP
Update table1 set name = i.name, desc = i.desc where id = i.id and (name is null or desc is null);
END LOOP;
END;
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.