In this article, I will walk you through professional-grade methods for performing cross-table updates in SQL Server, from standard joins to advanced merge logic.
SQL Server Update Table From Another Table
Manual updates are out of the question for anything over a dozen rows. We need a way to tell SQL Server: “Look at Table B, find the matching ID in Table A, and change the price to match.”
Method 1: The UPDATE JOIN Syntax (The “Industry Standard”)
In my experience, the UPDATE...FROM...JOIN syntax is the most readable and commonly used method in American dev shops. It allows you to use the familiar JOIN logic to link your target and source.
The Logic and Syntax
The key here is that the UPDATE clause refers to the alias of the table, not the full table name again in the middle of the statement.
SQL
UPDATE target
SET target.RetailPrice = source.NewPrice,
target.LastUpdated = GETDATE()
FROM Production_Products AS target
INNER JOIN Staging_PriceUpdate AS source
ON target.ProductID = source.ProductID;Why This Works Well
- Efficiency: It uses the SQL Query Optimizer to find the most efficient path between indexes.
- Multi-Column Updates: You can update ten columns just as easily as one.
- Filtering: You can add a
WHEREclause to ensure you only update rows that actually changed.
Method 2: The MERGE Statement
If you are a Senior Architect at a tech firm, you likely prefer the MERGE statement. Introduced in SQL Server 2008, MERGE (often called “UPSERT”) allows you to handle Updates, Inserts, and Deletions in a single atomic transaction.
When to Use MERGE
Use MERGE when the source table might contain new rows that don’t exist in the target yet, or when you want to handle “Deletes” for rows no longer present in the source.
| Action | Scenario |
| MATCHED | The ID exists in both; Update the target. |
| NOT MATCHED BY TARGET | The ID is in Source but not Target; Insert it. |
| NOT MATCHED BY SOURCE | The ID is in Target but not Source; Delete it (optional). |
MERGE Example Logic
SQL
MERGE Production_Inventory AS Target
USING Staging_Inventory AS Source
ON (Target.SKU = Source.SKU)
WHEN MATCHED THEN
UPDATE SET Target.Quantity = Source.Quantity
WHEN NOT MATCHED BY TARGET THEN
INSERT (SKU, Quantity) VALUES (Source.SKU, Source.Quantity);
Method 3: The Subquery Approach
Before the JOIN syntax became the standard, we used subqueries. While I find this less readable for large datasets, it is useful for simple, single-column updates.
SQL
UPDATE Production_Products
SET RetailPrice = (SELECT NewPrice
FROM Staging_PriceUpdate
WHERE Staging_PriceUpdate.ProductID = Production_Products.ProductID)
WHERE EXISTS (SELECT 1
FROM Staging_PriceUpdate
WHERE Staging_PriceUpdate.ProductID = Production_Products.ProductID);
Warning: The WHERE EXISTS clause is mandatory here. Without it, any row in your target table that doesn’t have a match in the source will have its value set to NULL.
Performance Benchmarking: Which Method is Faster?
| Method | Speed (Small Data) | Speed (Large Data) | Complexity |
| UPDATE JOIN | Excellent | Excellent | Low |
| MERGE | Good | Moderate | Medium |
| Subquery | Good | Poor | Medium |
Key Takeaway: For pure updates, the JOIN syntax usually wins on performance. MERGE carries slightly more overhead because it has to manage the logic for three different potential actions.
Critical Safety Measures
Updating data is a destructive action. Once you COMMIT, the old data is gone. In my decade of consulting, I follow a strict protocol before running any cross-table update.
1. The “Select Before Update” Rule
Never run an UPDATE without first running it as a SELECT.
- Change your
UPDATE target SET...toSELECT target.OldVal, source.NewVal. - Verify at least 10–20 rows manually to ensure your
JOINlogic isn’t creating a “Cartesian Product” (where every row matches every other row).
2. Use Transactions
Always wrap your update in a transaction block. This is the “Undo” button of the SQL world.
SQL
BEGIN TRANSACTION;
-- Run your update here
UPDATE target ...
-- CHECK YOUR RESULTS!
-- SELECT COUNT(*) FROM target WHERE ...
-- If it looks good:
COMMIT;
-- If you messed up:
-- ROLLBACK;
3. Check Row Counts
After the update, SQL Server will report (X row(s) affected). If you expected to update 500 rows and it says 5,000,000, hit ROLLBACK immediately.
Best Practices
If you are working with tables containing hundreds of millions of rows, standard updates can bloat the Transaction Log.
- Batching: Update in chunks of 5,000 or 10,000 rows using a
WHILEloop. This prevents the log from filling up the disk and allows other transactions to sneak in between batches. - Indexing: Ensure that the columns used in the
JOIN(usually the Primary Key) are indexed on both tables. A missing index on a million-row update can turn a 5-second task into a 5-hour nightmare. - Disable Triggers: If the target table has audit triggers, consider disabling them if you are doing a massive one-time migration to speed up the process—just ensure you document the change for your compliance team.
Conclusion:
Updating a table from another table is a routine task, but it requires atention. Whether you choose the readability of the JOIN syntax or the power of the MERGE statement, the goal is always the same: Absolute Accuracy.
You may also like the following articles:
- How To Find Who Updated The Table In SQL Server
- Update Stats on Table SQL Server
- How to Recover a Deleted Table in SQL Server Without Backup
After working for more than 15 years in the Software field, especially in Microsoft technologies, I have decided to share my expert knowledge of SQL Server. Check out all the SQL Server and related database tutorials I have shared here. Most of the readers are from countries like the United States of America, the United Kingdom, New Zealand, Australia, Canada, etc. I am also a Microsoft MVP. Check out more here.