Skip to content

SQL - Update Join

SQL - Updating Data Across Tables with UPDATE JOIN

Section titled “SQL - Updating Data Across Tables with UPDATE JOIN”

In relational databases, data is often normalized and spread across multiple tables. While the standard UPDATE statement modifies a single table, real-world scenarios frequently require updating one table based on values from another. This is where the powerful, albeit database-specific, UPDATE ... JOIN (or equivalent) syntax becomes essential.

For instance, in an e-commerce system, when a customer’s order is fulfilled, you might need to update the orders table to set the status to ‘Shipped’ and simultaneously decrement the stock_quantity in the products table. Performing these related updates atomically is crucial for data integrity.

A cross-table update combines an UPDATE statement with a JOIN clause. This allows you to define a relationship between the target table (the one being updated) and a source table (the one providing the new values or conditions). The JOIN identifies which rows in the target table correspond to specific rows in thesource table, and the SET clause then performs the update.

Important: The syntax for performing an update with a join is not part of the ANSI SQL standard and varies significantly between different database systems like PostgreSQL, MySQL, and SQL Server. It’s critical to use the correct syntax for your specific database.

Let’s review the syntax for the most common database management systems.

UPDATE target_table
SET column1 = source_table.new_value1
FROM source_table
WHERE target_table.join_column = source_table.join_column;
UPDATE target_table
JOIN source_table ON target_table.join_column = source_table.join_column
SET target_table.column1 = source_table.new_value1;
UPDATE target_table
SET column1 = source_table.new_value1
FROM target_table
JOIN source_table ON target_table.join_column = source_table.join_column;

Let’s consider a realistic e-commerce scenario. We have a products table with current inventory and a sales table that records new sales. We need to decrease the stock quantity in products after a sale is made.

First, let’s create and populate our tables. Note the use of appropriate data types like INT and TIMESTAMP.

-- Table to store product information and inventory
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(100) NOT NULL,
stock_quantity INT NOT NULL CHECK (stock_quantity >= 0)
);
-- Table to record sales transactions
CREATE TABLE sales (
sale_id INT PRIMARY KEY,
product_id INT NOT NULL,
quantity_sold INT NOT NULL,
sale_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
-- Insert initial stock
INSERT INTO products (product_id, product_name, stock_quantity) VALUES
(101, 'Wireless Mouse', 50),
(102, 'USB-C Cable', 120);
-- Record a new sale
INSERT INTO sales (sale_id, product_id, quantity_sold) VALUES
(1, 101, 5);

Now, let’s write a query to update the products table based on the new sale. We will use the PostgreSQL syntax for this example.

-- Update query using PostgreSQL syntax
UPDATE products
SET stock_quantity = products.stock_quantity - sales.quantity_sold
FROM sales
WHERE products.product_id = sales.product_id AND sales.sale_id = 1;

To confirm the update was successful, you can query the products table.

SELECT * FROM products WHERE product_id = 101;

The result will show that the stock for ‘Wireless Mouse’ has been reduced.

product_idproduct_namestock_quantity
101Wireless Mouse45
  • Use Transactions: When performing updates that must succeed or fail together (like updating orders and inventory), always wrap your statements in a transaction (BEGIN; ... COMMIT; or ROLLBACK;). This ensures data atomicity.
  • Test with SELECT: Before running a destructive UPDATE query, write a SELECT statement with the exact same JOIN and WHERE clauses. This allows you to preview which rows will be affected without changing any data.
  • Be Explicit with Aliases: In complex joins, use table aliases (e.g., UPDATE p SET ... FROM products AS p JOIN ...) to improve readability and prevent errors from ambiguous column names.
  • Index Join Columns: Ensure that the columns used in your JOIN conditions (product_id in our example) are indexed. This dramatically improves the performance of the update operation on large tables.

Further Learning: Using CTEs for Complex Updates

Section titled “Further Learning: Using CTEs for Complex Updates”

For more complex scenarios, such as when the new values need to be calculated through several steps, Common Table Expressions (CTEs) can make your UPDATE statement more readable and maintainable. You can perform complex aggregations or transformations in the CTE and then join to it in the final UPDATE.

-- Example concept using a CTE in PostgreSQL
WITH aggregated_sales AS (
SELECT
product_id,
SUM(quantity_sold) AS total_sold
FROM recent_sales_batch
GROUP BY product_id
)
UPDATE products p
SET stock_quantity = p.stock_quantity - ag.total_sold
FROM aggregated_sales ag
WHERE p.product_id = ag.product_id;