PostgreSQL & SQL Server: UPDATE...FROM

postgres-update-from.sql
-- PostgreSQL
UPDATE products p
SET price = s.new_price
FROM price_updates s
WHERE p.sku = s.sku;
sqlserver-update-from.sql
-- SQL Server
UPDATE p
SET p.price = s.new_price
FROM products p
INNER JOIN price_updates s ON p.sku = s.sku;

Both databases add a FROM clause to the UPDATE statement to bring in the second table. PostgreSQL puts the join condition in WHERE; SQL Server conventionally uses an explicit INNER JOIN inside the FROM clause, though a WHERE-based join also works there.

MySQL: UPDATE JOIN

mysql-update-join.sql
UPDATE products p
JOIN price_updates s ON p.sku = s.sku
SET p.price = s.new_price;

MySQL folds the join directly into the UPDATE statement rather than using a separate FROM clause — the join comes right after naming the table being updated, and SET comes after the join condition instead of before it.

Oracle: updatable subquery or MERGE

oracle-updatable-subquery.sql
UPDATE (
    SELECT p.price AS old_price, s.new_price
    FROM products p, price_updates s
    WHERE p.sku = s.sku
)
SET old_price = new_price;
oracle-merge-alternative.sql
MERGE INTO products p
USING price_updates s
ON (p.sku = s.sku)
WHEN MATCHED THEN UPDATE SET p.price = s.new_price;

Oracle has no UPDATE...FROM syntax at all. The classic approach wraps the join in a subquery and updates its output directly — which requires the join column on the inner (non-updated) side to be declared unique or backed by a primary key, or Oracle raises ORA-01779. MERGE is the more explicit modern alternative and doesn't have that restriction in the same way, since WHEN MATCHED makes the intent unambiguous.

The multi-match trap

Every one of these forms shares the same hazard: if the join matches more than one row on the source side for a given target row, the database still only writes one value — but which of the matching rows supplies it is unspecified and can differ by query plan, database version, or even between runs on the exact same data.

price_updates has 2 rows for sku 'ABC123'
skunew_price
ABC12319.99
ABC12324.99
Result: unpredictable, not an error
products.price after UPDATE
Either 19.99 or 24.99 — not guaranteed which

No error is raised in most databases — the statement runs, appears to succeed, and quietly leaves the row in a state that depends on internal row-processing order rather than anything meaningful in the data. The fix is always the same: confirm the join column is unique on the source side before running the update, either with a quick GROUP BY ... HAVING COUNT(*) > 1 check or an actual unique constraint.

Key takeaways

  • PostgreSQL/SQL Server: UPDATE ... SET ... FROM source WHERE join-condition. MySQL: UPDATE t JOIN source ON join-condition SET ....
  • Oracle has no UPDATE...FROM — use an updatable subquery or MERGE instead.
  • Oracle's updatable-subquery form requires a unique/primary key on the source join column, or it raises ORA-01779.
  • If the join matches multiple source rows per target row in any database, the row actually used is unspecified — always verify the source join column is unique first.