Oracle SQL: Perbarui tabel dengan data dari tabel lain

251

Tabel 1:

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

Meja 2:

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

Di oracle SQL, bagaimana cara menjalankan kueri pembaruan sql yang dapat memperbarui Tabel 1 dengan Tabel 2 namedan descmenggunakan yang sama id? Jadi hasil akhirnya yang akan saya dapatkan adalah

Tabel 1:

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

Pertanyaan diambil dari memperbarui satu tabel dengan data dari yang lain , tetapi khusus untuk Oracle oracle.

Muhd
sumber
2
kemungkinan duplikat kueri pembaruan sql dengan data dari tabel lain
p.campbell
Anda harus kembali ke pertanyaan Anda yang lain, tidak menerima jawaban itu, dan nyatakan secara khusus bahwa Anda memerlukan sintaks Oracle PLSQL.
p.campbell
3
@ p.campbell, Itu bukan pertanyaan saya ...
Muhd
1
Oh begitu. Jadi Anda menyalin-menempelkan badan pertanyaan, tetapi dimodifikasi untuk memasukkan bit Oracle.
p.campbell
2
Ya. Dan ini mungkin bukan contoh terbaik karena "desc" adalah kata yang dilindungi undang-undang, tapi oh well.
Muhd

Jawaban:

512

Ini disebut pembaruan berkorelasi

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 )

Dengan asumsi hasil gabungan dalam tampilan yang dipertahankan kunci, Anda juga bisa

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
Gua Justin
sumber
8
Dalam contoh kode pertama Anda: Apakah klausa WHERE luar diperlukan untuk hasil yang benar? Atau apakah Anda menggunakannya hanya untuk mempercepat permintaan?
Mathias Bader
41
@totoro - Pada contoh pertama, WHERE EXISTSmencegah Anda memperbarui baris t1jika tidak ada baris yang cocok t2. Tanpa itu, setiap baris di t1akan diperbarui dan nilai-nilai akan ditetapkan NULLjika tidak ada baris yang cocok di t2. Itu umumnya bukan apa yang Anda inginkan terjadi sehingga WHERE EXISTSumumnya diperlukan.
Justin Cave
3
Perlu ditambahkan bahwa SELECT ... FROM t2 harus menghasilkan baris yang unik. Ini berarti bahwa Anda harus memilih pada semua bidang yang terdiri dari kunci unik - kunci primer non-unik tidak cukup. Tanpa keunikan, Anda direduksi menjadi sesuatu seperti loop @ PaulKarr - dan jika tidak ada korelasi unik, maka lebih dari satu baris target dapat diperbarui untuk setiap baris sumber.
Andrew Leach
2
Penjelasan tentang persyaratan terpelihara kunci untuk gabungan yang
Vadzim
1
@RachitSharma - Itu berarti bahwa subquery Anda (permintaan dari table2) mengembalikan beberapa baris untuk satu table1nilai atau lebih dan Oracle tidak tahu yang mana yang ingin Anda gunakan. Biasanya, itu berarti Anda harus memperbaiki subquery sehingga mengembalikan satu baris yang berbeda.
Justin Cave
132

Coba ini:

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;
Adrian
sumber
4
Sangat cepat sekali, 1159477 baris digabung dalam 15,5
jefissu
3
Saya harap semua orang mengunjungi pertanyaan ini setelah 2015 memperhatikan jawaban ini. Perhatikan bahwa ini juga berfungsi jika table1dan table2merupakan tabel yang sama, hanya mengurus -part ONdan WHERE-clause untuk SELECT-Statement of table2!
sjngm
1
Saya menemukan bahwa setiap kali saya perlu melakukan penggabungan lagi, saya terus kembali ke jawaban ini untuk mendapatkan inspirasi. Saya mungkin mencetaknya dan membingkainya di dinding saya
arnehehe
Bekerja seperti pesona !! Terima kasih!
davidwillianx
SELECT DISTINCT ID, FIELD1, FIELD1 DARI table2 WHERE ID NOT NOT NULL
Joseph Poirier
17

mencoba

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);
Yahia
sumber
4
Kelemahan dari ini adalah bahwa pernyataan SELECT diulang 3 kali. Dalam contoh kompleks yang bisa menjadi pemecah kesepakatan.
David Balažic
9
Update table set column = (select...)

tidak pernah bekerja untuk saya karena set hanya mengharapkan 1 nilai - SQL Error: ORA-01427: subquery baris tunggal mengembalikan lebih dari satu baris.

inilah solusinya:

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;

Begitulah tepatnya Anda menjalankannya di lembar kerja SQLDeveloper. Mereka bilang itu lambat tapi itu satu-satunya solusi yang bekerja untuk saya dalam kasus ini.

Pau Karr
sumber
adakah yang bisa menjelaskan mengapa ini layak mendapat -2 pada reputasi? LOL.
Pau Karr
13
Saya tidak down rate, tetapi itu bukan solusi yang baik. Pertama: jika subselect mengembalikan beberapa nilai, maka loop untuk akan menimpa nama pada table2 beberapa kali untuk beberapa / semua catatan (tidak bersih). Kedua: tidak ada urutan demi klausa sehingga hal ini akan terjadi dengan cara yang tidak dapat diprediksi (yaitu nilai terakhir dalam data yang tidak terurut menang). Ketiga: Ini akan jauh lebih lambat. Dengan asumsi hasil dari for loop dimaksudkan, subselect asli dapat ditulis ulang dengan cara yang terkontrol untuk mengembalikan hanya 1 nilai untuk setiap record ... cara yang dibuat paling sederhana adalah (pilih min (nama) ...)
Alternator
Inilah yang saya butuhkan. Terima kasih (+1)
Robert Hyatt
3
Jika Anda mendapatkan beberapa nilai dalam subquery Anda, Anda mungkin memikirkan kembali kueri dan menggunakan DISTINCT atau GROUP BY dengan MIN, MAX. Hanya sebuah ide.
Francis
Singkat cerita: jika Anda bisa menghindarinya, jangan pernah menggunakan LOOP dalam pernyataan T-SQL. Secara pribadi, jika bukan karena 0,001% dari waktu di mana tidak ada solusi lain, saya bahkan tidak berpikir itu seharusnya menjadi fungsi yang tersedia di T-SQL. T-SQL dirancang untuk berbasis set, sehingga bekerja pada seluruh set data secara keseluruhan; itu TIDAK boleh digunakan untuk bekerja pada data baris demi baris.
Ray K.
8

Tampaknya ada jawaban yang lebih baik dengan klausa 'in' yang memungkinkan beberapa kunci untuk bergabung :

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

Daging sapi memiliki kolom yang ingin Anda gunakan sebagai kunci dalam tanda kurung di mana klausa sebelum 'dalam' dan memiliki pernyataan pilih dengan nama kolom yang sama dalam tanda kurung. di mana ( kolom1, kolom2 ) di ( pilih ( kolom1, kolom2 ) dari tabel di mana "set yang saya inginkan" );

semut
sumber
Tautan kedaluwarsa. ( 404)
Dumbo
-3

Jika tabel Anda t1 dan cadangannya t2 memiliki banyak kolom, inilah cara ringkas untuk melakukannya.

Selain itu, masalah saya yang terkait adalah bahwa hanya beberapa kolom yang dimodifikasi dan banyak baris tidak diedit ke kolom ini, jadi saya ingin membiarkannya sendiri - pada dasarnya mengembalikan subset kolom dari cadangan seluruh tabel. Jika Anda hanya ingin mengembalikan semua baris, lewati klausa di mana.

Tentu saja cara yang lebih sederhana adalah menghapus dan menyisipkan sebagai pilih, tetapi dalam kasus saya, saya membutuhkan solusi hanya dengan pembaruan.

Kuncinya adalah ketika Anda memilih * dari sepasang tabel dengan nama kolom duplikat, yang ke-2 akan dinamai _1. Jadi, inilah yang saya pikirkan:

  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, ...
Jim P
sumber
Ini tidak berfungsi untuk saya di Oracle 11g. Bisakah Anda membuat contoh metode ini?
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;
Avila Theresa
sumber