Modifying or deleting rows in one table based on a join condition with one or more other tables in a single DML statement.

PostgreSQL and SQL Server UPDATE ... FROM syntax allows joining additional tables in an UPDATE. More flexible than standard SQL correlated subquery approach for multi-table updates.

Compatibility

Filter by Database
SQL MULTI-TABLE UPDATE / DELETE Compatibility Across Databases
Database System Support Status Since Version Notes
MySQL Native 4.0 Multi-table UPDATE and DELETE with explicit JOIN syntax are native. Only the target table's rows are modified; joining tables are read-only in the statement.
PostgreSQL Native 7.2 Uses UPDATE ... FROM and DELETE ... USING syntax. The target table appears once; joined tables are in the FROM/USING clause.
SQL Server Native 2000 UPDATE ... FROM and DELETE with FROM clause. Can also use MERGE for upsert-style multi-table DML. The aliased target table in FROM is the idiomatic form.
Oracle Native 9i Oracle does not support UPDATE...JOIN directly. Use a correlated subquery, a CTE with MERGE, or update an inline view (if the view is key-preserved).
SQLite Native 3.33.0 UPDATE FROM syntax added in 3.33.0 (2020). DELETE with correlated subquery has always been available; DELETE...FROM is not supported — use WHERE EXISTS or WHERE id IN (subquery).

Details

This is one of the more fragmented areas across engines. MySQL's explicit JOIN in UPDATE/DELETE is intuitive but non-standard. PostgreSQL and SQL Server both use FROM/USING clauses, but differ in where the target table appears. Oracle is the most restrictive: no JOIN in UPDATE at all — correlated subqueries or the inline-view trick are the workarounds, and the inline-view approach requires the join to be key-preserved (Oracle must be able to prove which base-table row to update). SQLite gained UPDATE FROM relatively recently (3.33.0); scripts targeting older SQLite deployments need the subquery form. Cross-engine portability is best achieved with correlated subqueries (UPDATE t SET col = (SELECT ...) WHERE EXISTS (...)), which work on all five engines.

Standard Syntax

-- MySQL style UPDATE t1 JOIN t2 ON t1.id = t2.id SET t1.col = t2.val WHERE t2.flag = 1;

Version Support

MySQL: Native since 4.0 PostgreSQL: Native since 7.2 SQL Server: Native since 2000 Oracle: Native since 9i SQLite: Native since 3.33.0

Per-Database Syntax & Notes

MySQL Native syntax

Multi-table UPDATE and DELETE with explicit JOIN syntax are native. Only the target table's rows are modified; joining tables are read-only in the statement.

UPDATE orders o JOIN customers c ON o.customer_id = c.id SET o.priority = 'high' WHERE c.tier = 'gold'; DELETE o FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.active = 0;

PostgreSQL Native syntax

Uses UPDATE ... FROM and DELETE ... USING syntax. The target table appears once; joined tables are in the FROM/USING clause.

UPDATE orders o SET priority = 'high' FROM customers c WHERE o.customer_id = c.id AND c.tier = 'gold'; DELETE FROM orders o USING customers c WHERE o.customer_id = c.id AND c.active = false;

SQL Server Native syntax

UPDATE ... FROM and DELETE with FROM clause. Can also use MERGE for upsert-style multi-table DML. The aliased target table in FROM is the idiomatic form.

UPDATE o SET o.priority = 'high' FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.tier = 'gold'; DELETE o FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.active = 0;

Oracle Native syntax

Oracle does not support UPDATE...JOIN directly. Use a correlated subquery, a CTE with MERGE, or update an inline view (if the view is key-preserved).

-- Correlated subquery: UPDATE orders o SET o.priority = 'high' WHERE EXISTS ( SELECT 1 FROM customers c WHERE c.id = o.customer_id AND c.tier = 'gold' ); -- Key-preserved inline view: UPDATE ( SELECT o.priority, c.tier FROM orders o JOIN customers c ON o.customer_id = c.id ) v SET v.priority = 'high' WHERE v.tier = 'gold';

SQLite Native syntax

UPDATE FROM syntax added in 3.33.0 (2020). DELETE with correlated subquery has always been available; DELETE...FROM is not supported — use WHERE EXISTS or WHERE id IN (subquery).

-- UPDATE FROM (3.33.0+): UPDATE orders SET priority = 'high' FROM customers WHERE orders.customer_id = customers.id AND customers.tier = 'gold'; -- DELETE via subquery: DELETE FROM orders WHERE customer_id IN ( SELECT id FROM customers WHERE active = 0 );