961

I want to update a column in a table making a join on other table e.g.:

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'

But it is complaining :

Msg 170, Level 15, State 1, Line 2
Line 2: Incorrect syntax near 'a'.

What is wrong here?

shA.t
  • 16,580
  • 5
  • 54
  • 111
Manjot
  • 11,166
  • 9
  • 38
  • 49

13 Answers13

1791

You don't quite have SQL Server's proprietary UPDATE FROM syntax down. Also not sure why you needed to join on the CommonField and also filter on it afterward. Try this:

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

If you're doing something silly - like constantly trying to set the value of one column to the aggregate of another column (which violates the principle of avoiding storing redundant data), you can use a CTE (common table expression) - see here and here for more details:

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

The reason this is silly, is that you're going to have to re-run this entire update every single time any row in table2 changes. A SUM is something you can always calculate at runtime and, in doing so, never have to worry that the result is stale.

Aaron Bertrand
  • 272,866
  • 37
  • 466
  • 490
  • 6
    When I try this, it doesn't like `UPDATE table1 a SET a.[field] = b.[field]` -- removing the a alias does work, so `UPDATE table1 a SET [field] = b.[field] ` – baldmosher Jan 07 '16 at 13:56
  • 1
    @baldmosher I bet there is another issue, could you post a repro on SQL fiddle? – Aaron Bertrand Jan 07 '16 at 14:31
  • 4
    Didn't work for me on MySQL. I had to use the following (which makes more sense): `UPDATE t1 INNER JOIN t2 on t2.col = t1.col SET t1.field=value WHERE t2.col=something`. – George Jun 15 '16 at 21:39
  • 27
    @GeorgeRappel of course, probably won't work on many other platforms either. The question is about SQL Server. – Aaron Bertrand Jun 15 '16 at 22:57
  • 1
    Let's say multiple records from t1 referenced the same record from t2 so the join results in the same t2 record returned in multiple rows. In your first example, if you instead updated t2, would it update that record multiple times or just once? – xr280xr Oct 13 '17 at 17:44
  • 1
    @AaronBertrand If you were going to do the "silly" thing, wouldn't it be better to use a trigger instead? I can think of an application where you might want to store the aggregate of certain values for running analytics on them at a later date, especially if the operation you did on the data was more complicated than a simple aggregate of a column. – Aran Mulholland Nov 27 '17 at 07:42
  • 1
    @Aran Maybe, I don't know. If you need a row maintained for each day of all of time to look at later, sure, you couldn't wait and look at the data later. That didn't seem to be the requirement here - just a request to store redundant information, probably with the assumption that a user calculating the SUM would be much more costly than a trigger doing it (potentially much more often). – Aaron Bertrand Nov 27 '17 at 21:06
62

Try it like this:

    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'
RBarryYoung
  • 55,398
  • 14
  • 96
  • 137
  • 1
    why using a transaction? – CervEd Dec 23 '20 at 11:18
  • 14
    @CervEd Because the original question had the transaction in it, I just fixed the OP's own code, then years later someone edited it out for no good reason.. One bad thing about StackOverflow is that people make unnecessary edits to original questions just so they can get the editor badges, but these carless edits can make the already posted answers look odd or even nonsensical. – RBarryYoung Dec 23 '20 at 14:47
  • 3
    thanks, I wasn't aware OPs question was edited so it just made me wonder if there was a particular reason for using a transaction that wasn't obvious to me – CervEd Dec 25 '20 at 10:31
41

Answer given above by 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';

Just want to add why this problem occurs in SQL Server when we try to use alias of a table while updating that table, below mention syntax will always give error:

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

case can be any if you are updating a single table or updating while using join.

Although above query will work fine in PL/SQL but not in SQL Server.

Correct way to update a table while using table alias in SQL Server is:

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

Hope it will help everybody why error came here.

shA.t
  • 16,580
  • 5
  • 54
  • 111
Ankur Bhutani
  • 3,079
  • 4
  • 29
  • 26
5
    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'

More alternatives here.

Arsen Khachaturyan
  • 7,904
  • 4
  • 42
  • 42
wut
  • 328
  • 1
  • 7
  • 19
4

Seems like SQL Server 2012 can handle the old update syntax of Teradata too:

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

If I remember correctly, 2008R2 was giving error when I tried similar query.

nyunyu
  • 51
  • 1
  • 12
    [Just because it's supported doesn't mean it's a good idea](https://sqlblog.org/blogs/aaron_bertrand/archive/2009/10/08/bad-habits-to-kick-using-old-style-joins.aspx). – Aaron Bertrand Oct 13 '14 at 17:02
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";
onedaywhen
  • 55,269
  • 12
  • 100
  • 138
3

I find it useful to turn an UPDATE into a SELECT to get the rows I want to update as a test before updating. If I can select the exact rows I want, I can update just those rows I want to update.

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
Devart
  • 119,203
  • 23
  • 166
  • 186
CW1255
  • 113
  • 1
  • 1
  • 6
2

Another approach would be to use 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 is part of the SQL Standard

-Also I'm pretty sure inner join updates are non deterministic.. Similar question here where the answer talks about that http://ask.sqlservercentral.com/questions/19089/updating-two-tables-using-single-query.html

Shane Neuville
  • 2,127
  • 14
  • 19
2

I think, this is what you are looking for.

UPDATE
    Table1
SET
    Table1.columeName =T1.columeName * T2.columeName
FROM 
    Table1 T1
    INNER JOIN Table2 T2
        ON T1.columeName = T2.columeName;
camille
  • 16,432
  • 18
  • 38
  • 60
Null
  • 21
  • 1
1

I had the same issue.. and you don't need to add a physical column.. cuz now you will have to maintain it.. what you can do is add a generic column in the select query:

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
Mahmoud Sayed
  • 151
  • 2
  • 10
1

Aaron's approach above worked perfectly for me. My update statement was slightly different because I needed to join based on two fields concatenated in one table to match a field in another table.

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

Those who are using MYSQL

UPDATE table1 INNER JOIN table2 ON table2.id = table1.id SET table1.status = 0 WHERE table1.column = 20
-3

Try:

UPDATE table1
SET CalculatedColumn = ( SELECT [Calculated Column] 
                         FROM table2 
                         WHERE table1.commonfield = [common field])
WHERE  BatchNO = '110'
SteveC
  • 15,808
  • 23
  • 102
  • 173
user140301
  • 59
  • 1
  • 1
  • 9
    I'm downvoting, because this will update *every* row in `table1`, not just the rows where there's a match on the common field between both tables (effectively a left join and not an inner join). – Cᴏʀʏ Jun 29 '15 at 17:24
  • 1
    @Cᴏʀʏ: You mean that it will update every row matching `BatchNo = '110'`, right? Did all of the downvotes come as a result of this effect, or did others have other reasons for down-voting? – palswim May 21 '19 at 21:01
  • 1
    I ask because some may accept that the UPDATE operation may set some of the rows to `NULL`, and this form may be a less T-SQL specific solution. – palswim May 21 '19 at 21:04
  • I upvoted that, as it worked for me and all other upvoted answers threw error in my case. thanks – saleh asadi Jan 12 '23 at 12:25