Perbarui tabel menggunakan GABUNG di SQL Server?


835

Saya ingin memperbarui kolom dalam tabel yang membuat gabungan di tabel lain misalnya:

UPDATE table1 a 
INNER JOIN table2 b ON a.commonfield = b.[common field] 
SET a.CalculatedColumn= b.[Calculated Column]
WHERE 
    b.[common field]= a.commonfield
AND a.BatchNO = '110'

Tapi itu mengeluh:

Msg 170, Level 15, State 1, Line 2
Line 2: Sintaksis salah dekat 'a'.

Apa yang salah di sini?

Jawaban:


1598

Anda tidak memiliki UPDATE FROMsintaks kepemilikan SQL Server turun. Juga tidak yakin mengapa Anda harus bergabung di CommonFielddan juga memfilternya sesudahnya. Coba ini:

UPDATE t1
  SET t1.CalculatedColumn = t2.[Calculated Column]
  FROM dbo.Table1 AS t1
  INNER JOIN dbo.Table2 AS t2
  ON t1.CommonField = t2.[Common Field]
  WHERE t1.BatchNo = '110';

Jika Anda melakukan sesuatu yang benar-benar konyol - seperti terus-menerus mencoba mengatur nilai satu kolom ke agregat kolom lain (yang melanggar prinsip menghindari penyimpanan data yang berlebihan), Anda dapat menggunakan CTE (ekspresi tabel umum) - lihat di sini dan di sini untuk lebih jelasnya:

;WITH t2 AS
(
  SELECT [key], CalculatedColumn = SUM(some_column)
    FROM dbo.table2
    GROUP BY [key]
)
UPDATE t1
  SET t1.CalculatedColumn = t2.CalculatedColumn
  FROM dbo.table1 AS t1
  INNER JOIN t2
  ON t1.[key] = t2.[key];

Alasan ini benar-benar konyol, adalah bahwa Anda harus menjalankan kembali seluruh pembaruan ini setiap kali setiap baris table2perubahan. A SUMadalah sesuatu yang selalu dapat Anda hitung saat runtime dan, dengan melakukan itu, tidak perlu khawatir bahwa hasilnya basi.


4
Ketika saya mencoba ini, itu tidak suka UPDATE table1 a SET a.[field] = b.[field] - menghapus alias tidak berfungsi, jadiUPDATE table1 a SET [field] = b.[field]
baldmosher

@ baldmosher Saya yakin ada masalah lain, bisakah Anda memposting repro tentang SQL biola?
Aaron Bertrand

1
Tidak berfungsi untuk saya di MySQL. Saya harus menggunakan berikut (yang lebih masuk akal): UPDATE t1 INNER JOIN t2 on t2.col = t1.col SET t1.field=value WHERE t2.col=something.
George

16
@ GeorgeRappel tentu saja, mungkin juga tidak akan bekerja pada banyak platform lain. Pertanyaannya adalah tentang SQL Server.
Aaron Bertrand

Katakanlah beberapa catatan dari t1 mereferensikan catatan yang sama dari t2 sehingga hasil gabungan dalam catatan t2 yang sama dikembalikan dalam beberapa baris. Dalam contoh pertama Anda, jika Anda memperbarui t2, apakah akan memperbarui catatan itu beberapa kali atau hanya sekali?
xr280xr

46

Coba seperti ini:

begin tran
    UPDATE a 
    SET a.CalculatedColumn= b.[Calculated Column]
    FROM table1 a INNER JOIN table2 b ON a.commonfield = b.[common field] 
    WHERE a.BatchNO = '110'
commit tran

29

Jawaban yang diberikan di atas oleh Aaron sempurna:

UPDATE a
  SET a.CalculatedColumn = b.[Calculated Column]
  FROM Table1 AS a
  INNER JOIN Table2 AS b
  ON a.CommonField = b.[Common Field]
  WHERE a.BatchNo = '110';

Hanya ingin menambahkan mengapa masalah ini terjadi di SQL Server ketika kami mencoba menggunakan alias dari tabel saat memperbarui tabel itu, di bawah ini disebutkan sintaks akan selalu memberikan kesalahan:

update tableName t 
set t.name = 'books new' 
where t.id = 1

kasing bisa apa saja jika Anda memperbarui satu tabel atau memperbarui saat menggunakan bergabung.

Meskipun permintaan di atas akan berfungsi dengan baik dalam PL / SQL tetapi tidak dalam SQL Server.

Cara yang benar untuk memperbarui tabel saat menggunakan alias tabel di SQL Server adalah:

update t 
set t.name = 'books new' 
from tableName t 
where t.id = 1

Semoga ini bisa membantu semua orang mengapa kesalahan datang ke sini.


1
Baik, terima kasih Jawaban Anda adalah yang benar untuk pertanyaan ini.
Ola Ström

4
MERGE table1 T
   USING table2 S
      ON T.CommonField = S."Common Field"
         AND T.BatchNo = '110'
WHEN MATCHED THEN
   UPDATE
      SET CalculatedColumn = S."Calculated Column";


2

Saya merasa berguna untuk mengubah PEMBARUAN menjadi SELECT untuk mendapatkan baris yang ingin saya perbarui sebagai tes sebelum memperbarui. Jika saya dapat memilih baris yang tepat yang saya inginkan, saya dapat memperbarui hanya baris yang ingin saya perbarui.

DECLARE @expense_report_id AS INT
SET @expense_report_id = 1027

--UPDATE expense_report_detail_distribution
--SET service_bill_id = 9

SELECT *
FROM expense_report_detail_distribution erdd
INNER JOIN expense_report_detail erd
INNER JOIN expense_report er 
    ON er.expense_report_id = erd.expense_report_id 
    ON erdd.expense_report_detail_id = erd.expense_report_detail_id
WHERE er.expense_report_id = @expense_report_id

2
    UPDATE mytable
         SET myfield = CASE other_field
             WHEN 1 THEN 'value'
             WHEN 2 THEN 'value'
             WHEN 3 THEN 'value'
         END
    From mytable
    Join otherTable on otherTable.id = mytable.id
    Where othertable.somecolumn = '1234'

Lebih banyak alternatif di sini .


0

Pendekatan lain adalah menggunakan MERGE

  ;WITH cteTable1(CalculatedColumn, CommonField)
  AS
  (
    select CalculatedColumn, CommonField from Table1 Where BatchNo = '110'
  )
  MERGE cteTable1 AS target
    USING (select "Calculated Column", "Common Field" FROM dbo.Table2) AS source ("Calculated Column", "Common Field")
    ON (target.CommonField = source."Common Field")
    WHEN MATCHED THEN 
        UPDATE SET target.CalculatedColumn = source."Calculated Column";

-Merge adalah bagian dari Standar SQL

-Juga saya cukup yakin bahwa pembaruan dalam gim tidak bersifat deterministik .. Pertanyaan serupa di sini di mana jawabannya berbicara tentang http://ask.sqlservercentral.com/questions/19089/updating-two-tables-using-single-query. html


4
Walaupun mungkin standar, saya akan sangat berhati-hatiMERGE .
Aaron Bertrand

1
Itu semua agak lucu karena secara harfiah 5 menit setelah saya memposting ini saya terjadi pada beberapa pembaruan non-deterministik bermasalah dalam sprocs yang saya warisi :-) hal
Shane Neuville

Itu tidak membuat penggabungan menjadi lebih baik, itu hanya berarti Anda memiliki pembaruan yang buruk.
Aaron Bertrand

1
Ya saya hanya menjadi anekdot :-) Saya punya ini di otak ketika saya menyelam kembali ke sproc dan itu adalah hal pertama yang saya lihat.
Shane Neuville

3
CTE adalah standar; tanda kurung untuk menghindari nama-nama konyol tidak (tanda kutip ganda).
onedaywhen

0

Saya memiliki masalah yang sama .. dan Anda tidak perlu menambahkan kolom fisik .. karena sekarang Anda harus memeliharanya .. yang dapat Anda lakukan adalah menambahkan kolom generik dalam kueri pemilihan:

EX:

select tb1.col1, tb1.col2, tb1.col3 ,
( 
select 'Match' from table2 as tbl2
where tbl1.col1 = tbl2.col1 and tab1.col2 = tbl2.col2
)  
from myTable as tbl1

0

Pendekatan Harun di atas bekerja dengan sempurna untukku. Pernyataan pembaruan saya sedikit berbeda karena saya harus bergabung berdasarkan dua bidang yang disatukan dalam satu tabel untuk mencocokkan bidang di tabel lain.

 --update clients table cell field from custom table containing mobile numbers

update clients
set cell = m.Phone
from clients as c
inner join [dbo].[COSStaffMobileNumbers] as m 
on c.Last_Name + c.First_Name = m.Name

-3

Mencoba:

UPDATE table1
SET CalculatedColumn = ( SELECT [Calculated Column] 
                         FROM table2 
                         WHERE table1.commonfield = [common field])
WHERE  BatchNO = '110'

7
Saya downvoting, karena ini akan memperbarui setiap baris table1, bukan hanya baris di mana ada kecocokan pada bidang umum di antara kedua tabel (efektif gabungan kiri dan bukan gabungan internal).
C

@ Cᴏʀʏ: Maksud Anda akan memperbarui setiap baris yang cocok BatchNo = '110', bukan? Apakah semua downvotes datang sebagai akibat dari efek ini, atau apakah orang lain memiliki alasan lain untuk memilih-down?
palswim

Saya bertanya karena beberapa mungkin menerima bahwa operasi UPDATE dapat mengatur beberapa baris NULL, dan formulir ini mungkin merupakan solusi spesifik kurang T-SQL.
palswim
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.