Update based on select to same table - AGAIN, and AGAIN - sql-server

In Microsoft SQL Server:
I have seen this question several times, but can't see anyone solving the problem:
UPDATE theTable t1
SET t1.col2 =
(SELECT (10 * (col1 + col2))
FROM theTable t2
WHERE t1.busRelAccount = t2.busRelAccount
AND t2.rowName = 'POS'
)
WHERE t1.busRelAccount = t2.busRelAccount
AND t1.rowName = 'INVENTORY'
;
Anyone having solved this problem without using CURSOR and loop the table?

Not 100% sure what you're trying to do - but most likely, you could write your UPDATE statement much simpler - something like this:
UPDATE t1
SET t1.col2 = 10 * (t2.col1 + t2.col2)
FROM theTable t1
INNER JOIN theTable t2 ON t1.busRelAccount = t2.busRelAccount
WHERE
t1.rowName = 'INVENTORY'
AND t2.rowName = 'POS'
;
Basically, you define a JOIN between the two tables (both being the same table, really) and you then define how to update the column of t1 based on columns from t2

Related

How to update NULL's in a SQL table using the matching values from another table (SQL Server) [duplicate]

I have a database with account numbers and card numbers. I match these to a file to update any card numbers to the account number so that I am only working with account numbers.
I created a view linking the table to the account/card database to return the Table ID and the related account number, and now I need to update those records where the ID matches the Account Number.
This is the Sales_Import table, where the account number field needs to be updated:
LeadID
AccountNumber
147
5807811235
150
5807811326
185
7006100100007267039
And this is the RetrieveAccountNumber table, where I need to update from:
LeadID
AccountNumber
147
7006100100007266957
150
7006100100007267039
I tried the below, but no luck so far:
UPDATE [Sales_Lead].[dbo].[Sales_Import]
SET [AccountNumber] = (SELECT RetrieveAccountNumber.AccountNumber
FROM RetrieveAccountNumber
WHERE [Sales_Lead].[dbo].[Sales_Import]. LeadID =
RetrieveAccountNumber.LeadID)
It updates the card numbers to account numbers, but the account numbers get replaced by NULL
I believe an UPDATE FROM with a JOIN will help:
MS SQL
UPDATE
Sales_Import
SET
Sales_Import.AccountNumber = RAN.AccountNumber
FROM
Sales_Import SI
INNER JOIN
RetrieveAccountNumber RAN
ON
SI.LeadID = RAN.LeadID;
MySQL and MariaDB
UPDATE
Sales_Import SI,
RetrieveAccountNumber RAN
SET
SI.AccountNumber = RAN.AccountNumber
WHERE
SI.LeadID = RAN.LeadID;
The simple Way to copy the content from one table to other is as follow:
UPDATE table2
SET table2.col1 = table1.col1,
table2.col2 = table1.col2,
...
FROM table1, table2
WHERE table1.memberid = table2.memberid
You can also add the condition to get the particular data copied.
For SQL Server 2008 + Using MERGE rather than the proprietary UPDATE ... FROM syntax has some appeal.
As well as being standard SQL and thus more portable it also will raise an error in the event of there being multiple joined rows on the source side (and thus multiple possible different values to use in the update) rather than having the final result be undeterministic.
MERGE INTO Sales_Import
USING RetrieveAccountNumber
ON Sales_Import.LeadID = RetrieveAccountNumber.LeadID
WHEN MATCHED THEN
UPDATE
SET AccountNumber = RetrieveAccountNumber.AccountNumber;
Unfortunately the choice of which to use may not come down purely to preferred style however. The implementation of MERGE in SQL Server has been afflicted with various bugs. Aaron Bertrand has compiled a list of the reported ones here.
Generic answer for future developers.
SQL Server
UPDATE
t1
SET
t1.column = t2.column
FROM
Table1 t1
INNER JOIN Table2 t2
ON t1.id = t2.id;
Oracle (and SQL Server)
UPDATE
t1
SET
t1.colmun = t2.column
FROM
Table1 t1,
Table2 t2
WHERE
t1.ID = t2.ID;
MySQL
UPDATE
Table1 t1,
Table2 t2
SET
t1.column = t2.column
WHERE
t1.ID = t2.ID;
For PostgreSQL:
UPDATE Sales_Import SI
SET AccountNumber = RAN.AccountNumber
FROM RetrieveAccountNumber RAN
WHERE RAN.LeadID = SI.LeadID;
Seems you are using MSSQL, then, if I remember correctly, it is done like this:
UPDATE [Sales_Lead].[dbo].[Sales_Import] SET [AccountNumber] =
RetrieveAccountNumber.AccountNumber
FROM RetrieveAccountNumber
WHERE [Sales_Lead].[dbo].[Sales_Import].LeadID = RetrieveAccountNumber.LeadID
I had the same problem with foo.new being set to null for rows of foo that had no matching key in bar. I did something like this in Oracle:
update foo
set foo.new = (select bar.new
from bar
where foo.key = bar.key)
where exists (select 1
from bar
where foo.key = bar.key)
Here's what worked for me in SQL Server:
UPDATE [AspNetUsers] SET
[AspNetUsers].[OrganizationId] = [UserProfile].[OrganizationId],
[AspNetUsers].[Name] = [UserProfile].[Name]
FROM [AspNetUsers], [UserProfile]
WHERE [AspNetUsers].[Id] = [UserProfile].[Id];
For MySql that works fine:
UPDATE
Sales_Import SI,RetrieveAccountNumber RAN
SET
SI.AccountNumber = RAN.AccountNumber
WHERE
SI.LeadID = RAN.LeadID
Thanks for the responses. I found a solution tho.
UPDATE Sales_Import
SET AccountNumber = (SELECT RetrieveAccountNumber.AccountNumber
FROM RetrieveAccountNumber
WHERE Sales_Import.leadid =RetrieveAccountNumber.LeadID)
WHERE Sales_Import.leadid = (SELECT RetrieveAccountNumber.LeadID
FROM RetrieveAccountNumber
WHERE Sales_Import.leadid = RetrieveAccountNumber.LeadID)
In case the tables are in a different databases. (MSSQL)
update database1..Ciudad
set CiudadDistrito=c2.CiudadDistrito
FROM database1..Ciudad c1
inner join
database2..Ciudad c2 on c2.CiudadID=c1.CiudadID
Use the following block of query to update Table1 with Table2 based on ID:
UPDATE Sales_Import, RetrieveAccountNumber
SET Sales_Import.AccountNumber = RetrieveAccountNumber.AccountNumber
where Sales_Import.LeadID = RetrieveAccountNumber.LeadID;
This is the easiest way to tackle this problem.
MS Sql
UPDATE c4 SET Price=cp.Price*p.FactorRate FROM TableNamea_A c4
inner join TableNamea_B p on c4.Calcid=p.calcid
inner join TableNamea_A cp on c4.Calcid=cp.calcid
WHERE c4..Name='MyName';
Oracle 11g
MERGE INTO TableNamea_A u
using
(
SELECT c4.TableName_A_ID,(cp.Price*p.FactorRate) as CalcTot
FROM TableNamea_A c4
inner join TableNamea_B p on c4.Calcid=p.calcid
inner join TableNamea_A cp on c4.Calcid=cp.calcid
WHERE p.Name='MyName'
) rt
on (u.TableNamea_A_ID=rt.TableNamea_B_ID)
WHEN MATCHED THEN
Update set Price=CalcTot ;
update from one table to another table on id matched
UPDATE
TABLE1 t1,
TABLE2 t2
SET
t1.column_name = t2.column_name
WHERE
t1.id = t2.id;
The below SQL someone suggested, does NOT work in SQL Server. This syntax reminds me of my old school class:
UPDATE table2
SET table2.col1 = table1.col1,
table2.col2 = table1.col2,
...
FROM table1, table2
WHERE table1.memberid = table2.memberid
All other queries using NOT IN or NOT EXISTS are not recommended. NULLs show up because OP compares entire dataset with smaller subset, then of course there will be matching problem. This must be fixed by writing proper SQL with correct JOIN instead of dodging problem by using NOT IN. You might run into other problems by using NOT IN or NOT EXISTS in this case.
My vote for the top one, which is conventional way of updating a table based on another table by joining in SQL Server. Like I said, you cannot use two tables in same UPDATE statement in SQL Server unless you join them first.
This is the easiest and best have seen for Mysql and Maria DB
UPDATE table2, table1 SET table2.by_department = table1.department WHERE table1.id = table2.by_id
Note: If you encounter the following error based on your Mysql/Maria DB version "Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences"
Then run the code like this
SET SQL_SAFE_UPDATES=0;
UPDATE table2, table1 SET table2.by_department = table1.department WHERE table1.id = table2.by_id
it works with postgresql
UPDATE application
SET omts_received_date = (
SELECT
date_created
FROM
application_history
WHERE
application.id = application_history.application_id
AND application_history.application_status_id = 8
);
update within the same table:
DECLARE #TB1 TABLE
(
No Int
,Name NVarchar(50)
,linkNo int
)
DECLARE #TB2 TABLE
(
No Int
,Name NVarchar(50)
,linkNo int
)
INSERT INTO #TB1 VALUES(1,'changed person data', 0);
INSERT INTO #TB1 VALUES(2,'old linked data of person', 1);
INSERT INTO #TB2 SELECT * FROM #TB1 WHERE linkNo = 0
SELECT * FROM #TB1
SELECT * FROM #TB2
UPDATE #TB1
SET Name = T2.Name
FROM #TB1 T1
INNER JOIN #TB2 T2 ON T2.No = T1.linkNo
SELECT * FROM #TB1
I thought this is a simple example might someone get it easier,
DECLARE #TB1 TABLE
(
No Int
,Name NVarchar(50)
)
DECLARE #TB2 TABLE
(
No Int
,Name NVarchar(50)
)
INSERT INTO #TB1 VALUES(1,'asdf');
INSERT INTO #TB1 VALUES(2,'awerq');
INSERT INTO #TB2 VALUES(1,';oiup');
INSERT INTO #TB2 VALUES(2,'lkjhj');
SELECT * FROM #TB1
UPDATE #TB1 SET Name =S.Name
FROM #TB1 T
INNER JOIN #TB2 S
ON S.No = T.No
SELECT * FROM #TB1
try this :
UPDATE
Table_A
SET
Table_A.AccountNumber = Table_B.AccountNumber ,
FROM
dbo.Sales_Import AS Table_A
INNER JOIN dbo.RetrieveAccountNumber AS Table_B
ON Table_A.LeadID = Table_B.LeadID
WHERE
Table_A.LeadID = Table_B.LeadID
MYSQL (This is my preferred way for restoring all specific column reasonId values, based on primary key id equivalence)
UPDATE `site` AS destination
INNER JOIN `site_copy` AS backupOnTuesday
ON backupOnTuesday.`id` = destination.`id`
SET destdestination.`reasonId` = backupOnTuesday.`reasonId`
This will allow you to update a table based on the column value not being found in another table.
UPDATE table1 SET table1.column = 'some_new_val' WHERE table1.id IN (
SELECT *
FROM (
SELECT table1.id
FROM table1
LEFT JOIN table2 ON ( table2.column = table1.column )
WHERE table1.column = 'some_expected_val'
AND table12.column IS NULL
) AS Xalias
)
This will update a table based on the column value being found in both tables.
UPDATE table1 SET table1.column = 'some_new_val' WHERE table1.id IN (
SELECT *
FROM (
SELECT table1.id
FROM table1
JOIN table2 ON ( table2.column = table1.column )
WHERE table1.column = 'some_expected_val'
) AS Xalias
)
Summarizing the other answers, there're 4 variants of how to update target table using data from another table only when "match exists"
Query and sub-query:
update si
set si.AccountNumber = (
select ran.AccountNumber
from RetrieveAccountNumber ran
where si.LeadID = ran.LeadID
)
from Sales_Import si
where exists (select * from RetrieveAccountNumber ran where ran.LeadID = si.LeadID)
Inner join:
update si
set si.AccountNumber = ran.AccountNumber
from Sales_Import si inner join RetrieveAccountNumber ran on si.LeadID = ran.LeadID
Cross join:
update si
set si.AccountNumber = ran.AccountNumber
from Sales_Import si, RetrieveAccountNumber ran
where si.LeadID = ran.LeadID
Merge:
merge into Sales_Import si
using RetrieveAccountNumber ran on si.LeadID = ran.LeadID
when matched then update set si.accountnumber = ran.accountnumber;
All variants are more-less trivial and understandable, personally I prefer "inner join" option. But any of them could be used and developer has to select "better option" according to his/her needs
From performance perspective variants with join-s are more preferable:
Oracle 11g
merge into Sales_Import
using RetrieveAccountNumber
on (Sales_Import.LeadId = RetrieveAccountNumber.LeadId)
when matched then update set Sales_Import.AccountNumber = RetrieveAccountNumber.AccountNumber;
For Oracle SQL try using alias
UPDATE Sales_Lead.dbo.Sales_Import SI
SET SI.AccountNumber = (SELECT RAN.AccountNumber FROM RetrieveAccountNumber RAN WHERE RAN.LeadID = SI.LeadID);
I'd like to add one extra thing.
Don't update a value with the same value, it generates extra logging and unnecessary overhead.
See example below - it will only perform the update on 2 records despite linking on 3.
DROP TABLE #TMP1
DROP TABLE #TMP2
CREATE TABLE #TMP1(LeadID Int,AccountNumber NVarchar(50))
CREATE TABLE #TMP2(LeadID Int,AccountNumber NVarchar(50))
INSERT INTO #TMP1 VALUES
(147,'5807811235')
,(150,'5807811326')
,(185,'7006100100007267039');
INSERT INTO #TMP2 VALUES
(147,'7006100100007266957')
,(150,'7006100100007267039')
,(185,'7006100100007267039');
UPDATE A
SET A.AccountNumber = B.AccountNumber
FROM
#TMP1 A
INNER JOIN #TMP2 B
ON
A.LeadID = B.LeadID
WHERE
A.AccountNumber <> B.AccountNumber --DON'T OVERWRITE A VALUE WITH THE SAME VALUE
SELECT * FROM #TMP1
ORACLE
use
UPDATE suppliers
SET supplier_name = (SELECT customers.customer_name
FROM customers
WHERE customers.customer_id = suppliers.supplier_id)
WHERE EXISTS (SELECT customers.customer_name
FROM customers
WHERE customers.customer_id = suppliers.supplier_id);
update table1 dpm set col1 = dpu.col1 from table2 dpu where dpm.parameter_master_id = dpu.parameter_master_id;
If above answers not working for you try this
Update Sales_Import A left join RetrieveAccountNumber B on A.LeadID = B.LeadID
Set A.AccountNumber = B.AccountNumber
where A.LeadID = B.LeadID

How to optimize this SQL Server query

I have following query, which is working as expected but taking approx 3 seconds to execute. Reason is large number of records. Can somebody please suggest any steps in order to improve performance?
Explanation :
Check to see value using Comp id and Default_Comp = 1
If not found, ignore the Default_Comp and check only based on Comp id
Still not found, ignore the join with table 2 and try to get by Comp id.
My code:
DECLARE #Finished_Comp VARCHAR(MAX) = NULL;
SELECT #Finished_Comp = MIN(tbl2.Finished_Comp)
FROM Table1 tbl1
INNER JOIN Table2 tbl2 ON tbl1.Sav_ID = tbl2.Sav_ID
WHERE Comp_ID = #Comp_ID AND tbl1.Default_Comp = 1
IF #Finished_Comp IS NULL
BEGIN
SELECT #Finished_Comp = MIN(tbl2.Finished_Comp)
FROM Table1 tbl1
INNER JOIN Table2 tbl2 ON tbl1.Sav_ID = tbl2.Sav_ID
WHERE Comp_ID = #Comp_ID
END
IF #Finished_Comp IS NULL
BEGIN
SELECT #Finished_Comp = MIN(Finished_Comp)
FROM Table1 tbl1
WHERE Comp_ID = #Comp_ID AND #Finished_Comp != ''
END
I tried to use COALESCE, but it's returning wrong results for Finished_Comp
You say in the comments
I strongly believe the query can be changed to some extent so that no
multiple queries need to be executed.
Yes you're right.
SELECT #Finished_Comp = COALESCE(MIN(CASE WHEN tbl1.Default_Comp = 1 THEN tbl2.Finished_Comp END),
MIN(tbl2.Finished_Comp),
MIN(CASE WHEN tbl1.Finished_Comp <> '' THEN tbl1.Finished_Comp END))
FROM Table1 tbl1
LEFT JOIN Table2 tbl2
ON tbl1.Sav_ID = tbl2.Sav_ID
WHERE tbl1.Comp_ID = #Comp_IDV
But at best this will only reduce execution time to a third of current (for the case that all three queries need to be executed).
You should consider adding indexes on
Table1 - Comp_ID, Sav_ID INCLUDE (Default_Comp, Finished_Comp)
Table2 - Sav_ID INCLUDE (Finished_Comp)
For potentially much larger improvements.

T-SQL - Update Table with data from the same table - Ambiguous table

I'm having trouble understanding why this query is not working. I get a message
The table '#PriceChanges' is ambiguous
The first mention of #PriceChanges is underlined
UPDATE #PriceChanges
SET MaxQty = MIN(ISNULL(PT.MinQty, 100000000))
FROM #PriceChanges P
LEFT JOIN #PriceChanges PT ON P.ChangeType = PT.ChangeType
AND P.ItemNo = PT.ItemNo
AND P.MinQty < PT.MinQty
So what I'm trying to achieve is setting the MAX quantity of a given line to the next MIN quantity found in the same table. If there's none found, then just make it a ridiculously high number (100,000,000)
The end result should look like something like this
MinQty MaxQty
-----------------
0 20
20 50
50 100
100 100000000
The ambiguity arises because the FROM clause of the UPDATE refers to the #PriceChanges table twice, so there is no way for SQL Server to know which of the two you intend to update. To resolve the ambiguity, instead of writing UPDATE #PriceChanges, use UPDATE P or UPDATE PT. Here's a trivial example:
create table #Test (id int, datum char(1));
insert #Test values (1, ' '), (2, ' ');
-- ERROR: The table '#Test' is ambiguous.
update #Test set datum = 'X' from #Test T1 inner join #Test T2 on T1.id = T2.id + 1;
-- CORRECT: Use the appropriate table alias to indicate which instance of #Test you want to update.
update T1 set datum = 'X' from #Test T1 inner join #Test T2 on T1.id = T2.id + 1;
Creating an intermediary table worked, I still wonder why this couldn't all be put into a single update
SELECT P.ChangeType, P.ItemNo, P.MinQty, MIN(PT.MinQty) AS MaxQty
INTO #MaxQty
FROM #PriceChanges P
LEFT JOIN #PriceChanges PT
ON P.ChangeType = PT.ChangeType
AND P.ItemNo = PT.ItemNo
AND P.MinQty < PT.MinQty
GROUP BY P.ChangeType, P.ItemNo, P.MinQty
UPDATE #PriceChanges
SET MaxQty = ISNULL(PM.MaxQty, 100000000)
FROM #PriceChanges P
LEFT JOIN #MaxQty PM
ON P.ChangeType = PM.ChangeType
AND P.ItemNo = PM.ItemNo
AND P.MinQty = PM.MinQty
I see no use for ISNULL(PT.MinQty, 100000000). MIN() ignores NULL values. And you don't need a self join. An updatable CTE or subquery works:
UPDATE pc
SET MaxQty = min_minqty
FROM (SELECT pc.*, MIN(pc.MinQty) OVER (PARTITION BY ItemNo, ChangeType) as min_minqty
FROM #PriceChanges pc
) pc
WHERE pc.MaxQty <> min_minqty;
EDIT:
You appear to want:
with pc as (
select pc.*,
lead(pc.MinQty) over (order by pc.MinQty) as next_MinQty
from #PriceChanges pc
)
update pc
set MaxQty = next_MinQty;

Updating DISTINCTROW in SQL Server [duplicate]

What would the syntax be to convert this MS Access query to run in SQL Server as it doesn't have a DistinctRow keyword
UPDATE DISTINCTROW [MyTable]
INNER JOIN [AnotherTable] ON ([MyTable].J5BINB = [AnotherTable].GKBINB)
AND ([MyTable].J5BHNB = [AnotherTable].GKBHNB)
AND ([MyTable].J5BDCD = [AnotherTable].GKBDCD)
SET [AnotherTable].TessereCorso = [MyTable].[J5F7NR];
DISTINCTROW [MyTable] removes duplicate MyTable entries from the results. Example:
select distinctrow items
items.item_number, items.name
from items
join orders on orders.item_id = items.id;
In spite of the join getting you the same item_number and name multiple times when there is more than one order for it, DISTINCTROW reduces this to one row per item. So the whole join is merely for assuring that you only select items for which exist at least one order. You don't find DISTINCTROW in any other DBMS as far as I know. Probably because it is not needed. When checking for existence, we use EXISTS of course (or IN for that matter).
You are joining MyTable and AnotherTable and expect for some reason to get the same MyTable record multifold for one AnotherTable record, so you use DISTINCTROW to only get it once. Your query would (hopefully) fail if you got two different MyTable records for one AnotherTable record.
What the update does is:
update anothertable
set tesserecorso = (select top 1 j5f7nr from mytable where mytable.j5binb = anothertable.gkbinb and ...)
where exists (select * from mytable where mytable.j5binb = anothertable.gkbinb and ...)
But this uses about the same subquery twice. So we'd want to update from a query instead.
The easiest way to get one result record per <some columns> in a standard SQL query is to aggregate data:
select *
from anothertable a
join
(
select j5binb, j5bhnb, j5bdcd, max(j5f7nr) as j5f7nr
from mytable
group by j5binb, j5bhnb, j5bdcd
) m on m.j5binb = a.gkbinb and m.j5bhnb = a.gkbhnb and m.j5bdcd = a.gkbdcd;
How to write an updateble query is different from one DBMS to another. Here is the final update statement for SQL-Server:
update a
set a.tesserecorso = m.j5f7nr
from anothertable a
join
(
select j5binb, j5bhnb, j5bdcd, max(j5f7nr) as j5f7nr
from mytable
group by j5binb, j5bhnb, j5bdcd
) m on m.j5binb = a.gkbinb and m.j5bhnb = a.gkbhnb and m.j5bdcd = a.gkbdcd;
The DISTINCTROW predicate in MS Access SQL removes duplicates across all fields of a table in join statements and not just the selected fields of query (which DISTINCT in practically all SQL dialects do). So consider selecting all fields in a derived table with DISTINCT predicate:
UPDATE [AnotherTable]
SET [AnotherTable].TessereCorso = main.[J5F7NR]
FROM
(SELECT DISTINCT m.* FROM [MyTable] m) As main
INNER JOIN [AnotherTable]
ON (main.J5BINB = [AnotherTable].GKBINB)
AND (main.J5BHNB = [AnotherTable].GKBHNB)
AND (main.J5BDCD = [AnotherTable].GKBDCD)
Another variant of the query.. (Too lazy to get the original tables).
But like the query above updates 35 rows =, so does this one
UPDATE [Albi-Anagrafe-Associati]
SET
[Albi-Anagrafe-Associati].CRegDitte = [055- Registri ditte].[CRegDitte],
[Albi-Anagrafe-Associati].NIscrTribunale = [055- Registri ditte].[NIscrTribunale],
[Albi-Anagrafe-Associati].NRegImprese = [055- Registri ditte].[NRegImprese]
FROM [055- Registri ditte]
WHERE EXISTS(
SELECT *
FROM [055- Registri ditte]-- [Albi-Anagrafe-Associati]
WHERE ([055- Registri ditte].GIBINB = [Albi-Anagrafe-Associati].GKBINB)
AND ([055- Registri ditte].GIBHNB = [Albi-Anagrafe-Associati].GKBHNB)
AND ([055- Registri ditte].GIBDCD = [Albi-Anagrafe-Associati].GKBDCD))
Update [AnotherTable]
Set [AnotherTable].TessereCorso = MyTable.[J5F7NR]
From [AnotherTable]
Inner Join
(
Select Distinct [J5BINB],[5BHNB],[J5BDCD]
,(Select Top 1 [J5F7NR] From MyTable) as [J5F7NR]
,[J5BHNB]
From MyTable
)as MyTable
On (MyTable.J5BINB = [AnotherTable].GKBINB)
AND (MyTable.J5BHNB = [AnotherTable].GKBHNB)
AND (MyTable.J5BDCD = [AnotherTable].GKBDCD)

Update a table using JOIN in SQL Server?

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?
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.
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'
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.
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";
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.
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.
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
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
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;
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
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
Those who are using MYSQL
UPDATE table1 INNER JOIN table2 ON table2.id = table1.id SET table1.status = 0 WHERE table1.column = 20
Try:
UPDATE table1
SET CalculatedColumn = ( SELECT [Calculated Column]
FROM table2
WHERE table1.commonfield = [common field])
WHERE BatchNO = '110'

Resources