SQL Server'da JOIN kullanarak bir tablo güncelleştirilsin mi?


835

Bir tablodaki bir sütunu diğer tabloda birleştirme yaparak güncellemek istiyorum örn .:

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'

Ama şikayet ediyor:

Msg 170, Seviye 15, Durum 1, Satır 2
Satır 2: 'a' yakınında yanlış sözdizimi.

Burada yanlış olan ne?

Yanıtlar:


1597

SQL Server'ın özel UPDATE FROMsözdizimine sahip değilsiniz . Ayrıca neden katılmanız CommonFieldve daha sonra filtrelemeniz gerektiğinden emin değilsiniz . Bunu dene:

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

Gerçekten aptalca bir şey yapıyorsanız - sürekli olarak bir sütunun değerini başka bir sütunun toplamına ayarlamaya çalışmak gibi (gereksiz verileri saklamaktan kaçınma ilkesini ihlal eder), bir CTE (ortak tablo ifadesi) kullanabilirsiniz - buraya bakın ve burada daha fazla ayrıntı için:

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

Bunun gerçekten saçma olmasının nedeni, table2değişikliklerin herhangi bir satırında bu güncellemenin her birini yeniden çalıştırmanız gerekecek olmasıdır . A SUM, çalışma zamanında her zaman hesaplayabileceğiniz bir şeydir ve bunu yaparken, sonucun eski olduğu konusunda endişelenmenize gerek yoktur.


3
Bunu denediğimde, sevmiyorum UPDATE table1 a SET a.[field] = b.[field] - bir takma adı kaldırmak işe yarıyor, bu yüzdenUPDATE table1 a SET [field] = b.[field]
baldmosher

@baldmosher Bahse girerim başka bir sorun var, SQL keman üzerinde bir repro gönderebilir misiniz?
Aaron Bertrand

1
MySQL'de benim için çalışmadı. I (daha mantıklı) aşağıdaki kullanmak zorunda kaldı: UPDATE t1 INNER JOIN t2 on t2.col = t1.col SET t1.field=value WHERE t2.col=something.
George

15
@GeorgeRappel, elbette, muhtemelen diğer birçok platformda çalışmaz. Soru SQL Server ile ilgili.
Aaron Bertrand

Diyelim ki t1'den gelen birden fazla kayıt, t2'den aynı kayda referans verdi, böylece birleştirme birden fazla satıra döndürülen aynı t2 kaydında sonuçlandı. İlk örneğinizde, bunun yerine t2'yi güncellediyseniz, bu kayıt birden çok kez mi yoksa yalnızca bir kez mi güncellenir?
xr280xr

46

Şöyle deneyin:

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

Yukarıda verilen cevap Aaron is perfect:

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

Bu tabloyu güncellerken bir tablonun diğer adını kullanmaya çalıştığımızda bu sorunun neden SQL Server'da oluştuğunu eklemek istiyorum, aşağıda sözdizimi her zaman hata verecektir:

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

Birleştirme kullanırken tek bir tabloyu güncelleştiriyorsanız veya güncelleme yapıyorsanız durum herhangi bir durum olabilir.

Yukarıdaki sorgu PL / SQL'de iyi çalışmasına rağmen SQL Server'da çalışmaz.

SQL Server'da tablo diğer adını kullanırken tabloyu güncellemenin doğru yolu:

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

Buraya neden hata geldiğini herkese yardımcı olacağını umuyoruz.


Güzel, teşekkürler. Cevabınız bu soru için doğru.
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

Güncellemeden önce bir test olarak güncellemek istediğim satırları almak için bir GÜNCELLEME SEÇİM'e dönüştürmeyi yararlı buluyorum. İstediğim satırları tam olarak seçebilirsem, sadece güncellemek istediğim satırları güncelleyebilirim.

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'

Burada daha fazla alternatif .


0

Başka bir yaklaşım MERGE kullanmak olacaktır

  ;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, SQL Standardının bir parçasıdır

-Ayrıca iç birleşim güncellemelerinin deterministik olmadığından eminim .. Cevabın http://ask.sqlservercentral.com/questions/19089/updating-two-tables-using-single-query hakkında konuştuğu benzer soru . html


3
Standart olsalar da, çok dikkatli olurdumMERGE .
Aaron Bertrand

1
Komik olan her şey çünkü tam olarak 5 dakika bunu yayınladıktan sonra ben :-) eğlenceli şeyler miras aldım sprocs bazı sorunlu deterministik güncellemeler oldu oldu
Shane Neuville

Bu birleşmeyi daha iyi hale getirmez, sadece kötü güncellemeleriniz olduğu anlamına gelir.
Aaron Bertrand

1
Evet, sadece anekdot oluyordum :-) Sproc'a geri döndüğümde beynim vardı ve ilk gördüğüm şey buydu.
Shane Neuville

2
CTE'ler Standarttır; aptal isimler kaçmak için köşeli parantez değildir (çift tırnak vardır).
gün

0

Ben aynı sorunu vardı .. ve fiziksel bir sütun eklemeniz gerekmez .. çünkü şimdi bunu korumak zorunda kalacak .. Yapabileceğiniz şey seçme sorgusunda genel bir sütun eklemektir:

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

Aaron'ın yukarıdaki yaklaşımı benim için mükemmel çalıştı. Güncelleme bildirimim biraz farklıydı, çünkü başka bir tablodaki bir alanı eşleştirmek için bir tabloda birleştirilen iki alana dayalı olarak katılmam gerekiyordu.

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

Deneyin:

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

6
Ben aşağı oy ediyorum, çünkü bu sadece her iki tablo arasındaki ortak alanda (etkili bir sol birleştirme ve bir iç birleştirme) bir maç olduğu satırları değil, her satırı güncelleyecektir table1.
Cᴏʀʏ

@ Cᴏʀʏ: Yani her satır eşleşmesini güncelleyecek BatchNo = '110', değil mi? Tüm aşağı oylar bu etkinin bir sonucu mu geldi, yoksa başkalarının aşağı oylama için başka nedenleri var mı?
palswim

Bazı güncelleştirme işleminin bazı satırları ayarlayabileceğini NULLve bu formun daha az T-SQL'e özgü bir çözüm olabileceğini kabul edebileceği için soruyorum .
palswim
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.