PostgreSQL & SQL Server: UPDATE...FROM
-- PostgreSQL
UPDATE products p
SET price = s.new_price
FROM price_updates s
WHERE p.sku = s.sku;
-- 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
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
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;
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.
| sku | new_price |
|---|---|
| ABC123 | 19.99 |
| ABC123 | 24.99 |
| 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 orMERGEinstead. - 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.