Bagaimana saya bisa melakukan pernyataan UPDATE dengan GABUNG di SQL Server?


1314

Saya perlu memperbarui tabel ini dalam SQL Server dengan data dari tabel 'induknya', lihat di bawah:

Meja: dijual

id (int)
udid (int)
assid (int)

Tabel: ud

id  (int)
assid  (int)

sale.assidberisi nilai yang benar untuk diperbarui ud.assid.

Permintaan apa yang akan melakukan ini? Saya sedang memikirkan jointetapi saya tidak yakin apakah itu mungkin.


3
RDBMS apa yang Anda gunakan? MySQL, SQL Server, Oracle, PostgreSQL atau yang lainnya?
Chris J

beberapa hubungan antar tabel? Bagaimana orang bisa tahu catatan mana dari penjualan yang sesuai dengan catatan mana dari ud? Apakah ini berdasarkan id sebagai kunci utama di kedua tabel?
Cătălin Pitiș

Bagaimana Anda dapat memperbarui UD? Hanya memiliki assid dan ID itu sendiri. Bisakah Anda memberikan contoh dalam hal nilai aktual yang ada, dan catatan yang ingin Anda ubah atau tambahkan sebagai hasil skrip?
Bernhard Hofmann


Jawaban:


2383

Sintaks sangat tergantung pada SQL DBMS yang Anda gunakan. Berikut adalah beberapa cara untuk melakukannya di ANSI / ISO (alias harus bekerja pada SQL DBMS), MySQL, SQL Server, dan Oracle. Maklum bahwa metode ANSI / ISO saya yang disarankan biasanya akan jauh lebih lambat daripada dua metode lainnya, tetapi jika Anda menggunakan SQL DBMS selain MySQL, SQL Server, atau Oracle, maka itu mungkin satu-satunya cara untuk pergi (mis. jika SQL DBMS Anda tidak mendukung MERGE):

ANSI / ISO:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where exists (
      select * 
      from sale 
      where sale.udid = ud.id
 );

MySQL:

update ud u
inner join sale s on
    u.id = s.udid
set u.assid = s.assid

SQL Server:

update u
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid

PostgreSQL:

update ud
  set assid = s.assid
from sale s 
where ud.id = s.udid;

Perhatikan bahwa tabel target tidak boleh diulang dalam FROMklausa untuk Postgres.

Peramal:

update
    (select
        u.assid as new_assid,
        s.assid as old_assid
    from ud u
        inner join sale s on
            u.id = s.udid) up
set up.new_assid = up.old_assid

SQLite:

update ud 
     set assid = (
          select sale.assid 
          from sale 
          where sale.udid = ud.id
     )
 where RowID in (
      select RowID 
      from ud 
      where sale.udid = ud.id
 );

3
Sepertinya saya yang set assid = s.assidseharusnya MySQL set u.assid = s.assid.
dotancohen

2
Dalam sintaks ANSI, apa yang terjadi jika SELECT setelah =pengembalian lebih dari satu baris?
Membuang Akun

2
@ ThrowawayAccount3Million Mungkin akan gagal. AFAIK, operasi semacam ini akan mengharapkan nilai skalar dan akan menimbulkan kesalahan jika diberi hasil yang ditetapkan sebagai gantinya.
Francis Lord

6
Saya berharap OP memilih beberapa nama yang lebih baik untuk tabel dan kolomnya !! ini tidak bisa dibaca / intuitif ...
S.Serpooshan

4
Postgre 9.3 hanya bekerja menggunakanupdate ud set assid = s.assid
StackUnder

143

Ini harus bekerja di SQL Server:

update ud 
set assid = sale.assid
from sale
where sale.udid = id

98

postgres

UPDATE table1
SET    COLUMN = value
FROM   table2,
       table3
WHERE  table1.column_id = table2.id
       AND table1.column_id = table3.id
       AND table1.COLUMN = value
       AND table2.COLUMN = value
       AND table3.COLUMN = value 

20
Jawabannya akan lebih berguna jika akan menggunakan nama tabel / kolom yang digunakan dalam pertanyaan. Mengapa ada 3 tabel dalam jawaban Anda?
alfonx

50

Pendekatan SQL standar akan menjadi

UPDATE ud
SET assid = (SELECT assid FROM sale s WHERE ud.id=s.id)

Pada SQL Server Anda bisa menggunakan gabungan

UPDATE ud
SET assid = s.assid
FROM ud u
JOIN sale s ON u.id=s.id

1
Dengan yang pertama, Anda tidak dapat mencocokkan pada 2+ kolom, tetapi bergabung dengan karya-karya hebat.
makciook

6
@makciook: ya? Anda bisa menambahkan lebih banyak ketentuan dalam WHEREklausa jika Anda ingin mencocokkan pada kolom tambahan.
siride

2
Hanya nit ... tapi saya pikir OP berarti sale.udid = ud.id. Dan bukan sale.id.
Skippy VonDrake

39

PostgreSQL :

CREATE TABLE ud (id integer, assid integer);
CREATE TABLE sales (id integer, udid integer, assid integer);

UPDATE ud
SET assid = sales.assid
FROM sales
WHERE sales.id = ud.id;

26

Permintaan pembaruan yang disederhanakan menggunakan BERGABUNG dengan beberapa tabel.

   UPDATE
        first_table ft
        JOIN second_table st ON st.some_id = ft.some_id
        JOIN third_table tt  ON tt.some_id = st.some_id
        .....
    SET
        ft.some_column = some_value
    WHERE ft.some_column = 123456 AND st.some_column = 123456

Catatan - first_table, second_table, third_table, dan some_column seperti 123456 adalah nama tabel demo, nama kolom dan id. Gantilah dengan nama yang valid.


16

Contoh lain mengapa SQL tidak benar-benar portabel.

Untuk MySQL adalah:

update ud, sale
set ud.assid = sale.assid
where sale.udid = ud.id;

Untuk info lebih lanjut baca beberapa pembaruan tabel: http://dev.mysql.com/doc/refman/5.0/en/update.html

UPDATE [LOW_PRIORITY] [IGNORE] table_references
    SET col_name1={expr1|DEFAULT} [, col_name2={expr2|DEFAULT}] ...
    [WHERE where_condition]

2
Memberi +1 pada komentar "mengapa SQL tidak benar-benar portabel"! Portabilitas sangat rapuh sehingga hanya mendeklarasikan variabel akan merusak portabilitas di antara banyak mesin basis data populer.
Jeff Moden

8

Teradata Aster menawarkan cara lain yang menarik bagaimana mencapai tujuan:

MERGE INTO ud --what trable should be updated
USING sale -- from what table/relation update info should be taken
ON ud.id = sale.udid --join condition
WHEN MATCHED THEN 
    UPDATE SET ud.assid = sale.assid; -- how to update

8

Saya berpikir SQL-Server yang ada di posisi atas akan bekerja untuk Sybase karena keduanya adalah T-SQL tetapi sayangnya tidak.

Untuk Sybase saya menemukan pembaruan harus di atas meja itu sendiri, bukan alias:

update ud
set u.assid = s.assid
from ud u
    inner join sale s on
        u.id = s.udid

7

Pernyataan berikut dengan kata kunci FROM digunakan untuk memperbarui beberapa baris dengan gabungan

UPDATE users 
set users.DivisionId=divisions.DivisionId
from divisions join users on divisions.Name=users.Division

7

MySQL

Anda akan mendapatkan kinerja terbaik jika Anda lupa di mana klausa dan menempatkan semua kondisi dalam ekspresi ON.

Saya pikir ini karena permintaan pertama harus bergabung dengan tabel kemudian menjalankan klausa di mana itu, jadi jika Anda dapat mengurangi apa yang diperlukan untuk bergabung maka itulah cara berpuasa untuk mendapatkan hasil / melakukan udpate.

Contoh

Skenario

Anda memiliki tabel pengguna. Mereka dapat masuk menggunakan nama pengguna atau email atau nomor akun mereka. Akun-akun ini bisa aktif (1) atau tidak aktif (0). Tabel ini memiliki 50.000 baris

Anda kemudian memiliki tabel pengguna untuk menonaktifkan sekaligus karena Anda tahu mereka semua telah melakukan sesuatu yang buruk. Namun tabel ini, memiliki satu kolom dengan nama pengguna, email, dan nomor akun dicampur. Ini juga memiliki indikator "has_run" yang perlu diatur ke 1 (benar) ketika telah dijalankan

Pertanyaan

UPDATE users User
    INNER JOIN
        blacklist_users BlacklistUser
        ON
        (
            User.username = BlacklistUser.account_ref
            OR
            User.email = BlacklistedUser.account_ref
            OR
            User.phone_number = BlacklistUser.account_ref
            AND
            User.is_active = 1
            AND
            BlacklistUser.has_run = 0
        )
    SET
        User.is_active = 0,
        BlacklistUser.has_run = 1;

Pemikiran

Jika kita harus bergabung hanya pada kondisi ATAU itu pada dasarnya perlu memeriksa setiap baris 4 kali untuk melihat apakah harus bergabung, dan berpotensi menghasilkan lebih banyak baris. Namun, dengan memberikan lebih banyak persyaratan, ia dapat "melewati" banyak baris jika tidak memenuhi semua persyaratan saat bergabung.

Bonus

Ini lebih mudah dibaca. Semua kondisi di satu tempat dan baris untuk memperbarui ada di satu tempat


4

Dan di MS ACCESS:

UPDATE ud 
INNER JOIN sale ON ud.id = sale.udid
SET ud.assid = sale.assid;

1
Sebagai peringatan, SET harus datang segera setelah definisi recordset! Saya baru saja mencoba untuk menyusun skenario serupa dalam database Access, yang membutuhkan klausa WHERE (tidak akan menerimanya sebagai kondisi ON yang valid). DI MANA harus datang terakhir untuk menghindari kesalahan sintaksis.
Dodecaphone


3
UPDATE tblAppraisalBasicData
SET tblAppraisalBasicData.ISCbo=1
FROM tblAppraisalBasicData SI INNER JOIN  aaa_test RAN ON SI.EmpID = RAN.ID

3

Coba yang ini, saya pikir ini akan bekerja untuk Anda

update ud

set ud.assid = sale.assid

from ud 

Inner join sale on ud.id = sale.udid

where sale.udid is not null

2

Untuk SQLite gunakan properti RowID untuk membuat pembaruan:

update Table set column = 'NewValue'
where RowID = 
(select t1.RowID from Table t1
join Table2 t2 on t1.JoinField = t2.JoinField
where t2.SelectValue = 'FooMyBarPlease');

1
Bisakah Anda menjelaskan ini sedikit?
Mohammed Noureldin

1
@MohammedNoureldin saya akan coba jelaskan. Masalahnya adalah bagaimana memperbarui tabel dengan hasil dari kueri pada Gabung menggunakan tabel yang sama. Pernyataan (sub-pilih) bertindak seperti gabungan dan mengembalikan bidang sistem, RowID, yang merupakan angka unik untuk setiap baris dalam tabel. Karena sub-pilih dapat mengembalikan beberapa baris, "di mana RowID =" memilih satu baris yang benar dari sub-pilih yang dihasilkan dan melakukan pembaruan ke kolom. Beri tahu saya jika Anda perlu lebih banyak klarifikasi atau perlu mengetahui variasi pada tema ini.
KeithTheBiped
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.