Looking to update table records using SELECT statement results? The most efficient approach is using an UPDATE with JOIN to directly connect your target table with the source data. This method offers superior performance and cleaner syntax compared to subqueries or complex MERGE operations for most scenarios.
UPDATE target_table SET column = source.column FROM target_table INNER JOIN source_table ON condition for the most reliable and performant updates.
Method 1: UPDATE with JOIN (Recommended Approach)
The UPDATE with JOIN method directly connects your target table to the source data, making it both readable and efficient. Here’s the fundamental syntax:
UPDATE target_table
SET target_table.column1 = source.column1,
target_table.column2 = source.column2
FROM target_table
INNER JOIN source_table AS source
ON target_table.id = source.id
WHERE additional_conditions;
Real-World Example: Employee Salary Updates
Let’s say you need to update employee salaries from an HR import table:
-- Update employee salaries from import data
UPDATE employees
SET employees.salary = salary_import.new_salary,
employees.last_updated = GETDATE()
FROM employees
INNER JOIN salary_import
ON employees.employee_id = salary_import.employee_id
WHERE salary_import.effective_date <= GETDATE();
| Database | JOIN Syntax Support | Key Differences |
|---|---|---|
| SQL Server | β Full FROM clause support | Uses FROM after SET clause |
| MySQL | β Multi-table UPDATE | JOIN comes after UPDATE clause |
| PostgreSQL | β UPDATE...FROM pattern | FROM clause after WHERE |
Method 2: UPDATE with Subquery
Subqueries work best for single-column updates or when you need complex filtering logic:
-- Update product prices from supplier catalog
UPDATE products
SET price = (
SELECT supplier_catalog.unit_price
FROM supplier_catalog
WHERE supplier_catalog.product_code = products.sku
)
WHERE EXISTS (
SELECT 1
FROM supplier_catalog
WHERE supplier_catalog.product_code = products.sku
);
Method 3: MERGE Statement (Advanced Synchronization)
MERGE handles complex scenarios where you need to insert, update, or delete records based on matching conditions:
-- Synchronize inventory levels from warehouse system
MERGE inventory AS target
USING warehouse_updates AS source
ON target.product_id = source.product_id
WHEN MATCHED THEN
UPDATE SET
target.quantity = source.current_stock,
target.last_sync = GETDATE()
WHEN NOT MATCHED BY TARGET THEN
INSERT (product_id, quantity, last_sync)
VALUES (source.product_id, source.current_stock, GETDATE())
WHEN NOT MATCHED BY SOURCE THEN
DELETE;
Database-Specific Implementations
MySQL Multi-Table UPDATE
UPDATE customers c
INNER JOIN address_updates au ON c.customer_id = au.customer_id
SET c.address = au.new_address,
c.city = au.new_city
WHERE au.verified = 1;
PostgreSQL UPDATE...FROM
UPDATE orders
SET shipping_cost = rate_table.cost
FROM shipping_rates rate_table
WHERE orders.destination_zone = rate_table.zone
AND orders.weight <= rate_table.max_weight;
Performance Optimization Strategies
π Index Optimization
- JOIN columns: Ensure both tables have indexes on JOIN condition columns
- WHERE clauses: Index any columns used in WHERE conditions
- Composite indexes: Consider multi-column indexes for complex conditions
π Batch Processing Large Updates
-- Process in batches to avoid lock timeouts
DECLARE @BatchSize INT = 10000;
WHILE @@ROWCOUNT > 0
BEGIN
UPDATE TOP(@BatchSize) target_table
SET column1 = source.column1
FROM target_table t
INNER JOIN source_table s ON t.id = s.id
WHERE t.processed = 0;
-- Mark as processed
UPDATE TOP(@BatchSize) target_table
SET processed = 1
WHERE processed = 0;
END
Common Pitfalls and Solutions
-- Test query first
SELECT t.id, t.current_value, s.new_value
FROM target_table t
INNER JOIN source_table s ON t.id = s.id
WHERE t.current_value != s.new_value;
Multiple Row Matches
Prevent unexpected results when source tables contain duplicate keys:
-- Use ROW_NUMBER() to handle duplicates
WITH ranked_source AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY id ORDER BY updated_date DESC) as rn
FROM source_table
)
UPDATE target_table
SET column1 = rs.column1
FROM target_table t
INNER JOIN ranked_source rs ON t.id = rs.id
WHERE rs.rn = 1;
Best Practices Checklist
- β Backup critical data before major updates
- β Use transactions for rollback capability
- β Test in staging environment first
- β Verify row counts match expectations
- β Monitor execution plans for performance issues
- β Handle NULL values explicitly in JOIN conditions
Frequently Asked Questions
β Can I update multiple columns from different tables in one statement?
Yes, you can update multiple columns from different source tables using multiple JOINs:
UPDATE orders o
SET o.customer_name = c.name,
o.shipping_cost = s.rate
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id
INNER JOIN shipping_rates s ON o.shipping_zone = s.zone;
β What happens if the JOIN finds no matching records?
When using INNER JOIN, only rows with matches will be updated. Rows without matches remain unchanged. Use LEFT JOIN if you want to update all rows in the target table.
β How do I handle transaction rollback for large updates?
Wrap your updates in explicit transactions with proper error handling:
BEGIN TRANSACTION;
BEGIN TRY
UPDATE target_table SET column1 = source.column1
FROM target_table t
INNER JOIN source_table s ON t.id = s.id;
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW;
END CATCH;
β Which method performs better: JOIN or subquery?
UPDATE with JOIN typically performs better because:
- The database optimizer can create better execution plans
- Joins are processed once, while subqueries may execute for each row
- Index usage is more efficient with JOINs
For more advanced SQL techniques, check out Microsoft's official UPDATE documentation or explore PostgreSQL's UPDATE syntax guide.