Menu

SQLite UPDATE: WHERE, Multiple Columns, and UPDATE FROM

How to change existing rows in SQLite — UPDATE syntax, the WHERE clause that keeps you safe, multi-column updates, and UPDATE ... FROM for cross-table edits.

This page includes runnable editors — edit, run, and see output instantly.

UPDATE Changes Existing Rows

INSERT adds new rows. UPDATE modifies rows that already exist. The shape is short and worth memorizing:

UPDATE table_name
SET column = value
WHERE condition;

A working example:

SET says what changes. WHERE says which rows. The rest of the table is left alone.

The WHERE Clause Is Not Optional in Practice

Technically, WHERE is optional. Practically, leaving it off is how junior engineers ruin their afternoon:

UPDATE users SET status = 'inactive';
-- every single user is now inactive

No filter means every row matches. SQLite will quietly oblige. Always write the WHERE first, then the SET — that habit alone prevents a lot of accidents.

If you're not sure your WHERE is right, run the same condition as a SELECT first:

Same condition, two statements. The SELECT is your dry run.

Updating Multiple Columns

Comma-separate the assignments inside a single SET. One SET, many columns:

One round-trip to the database, one row changed, three columns updated. Don't write three separate UPDATE statements when one will do.

Expressions on the Right of =

The value after = doesn't have to be a literal. It can be any expression — including one that references the column's current value:

price * 1.10 reads the existing price, multiplies, and writes the result back. SQLite evaluates the right side using the row's current values before any of this statement's assignments take effect, so you can reference several columns safely:

UPDATE products SET price = price * 1.10, stock = stock + price;
-- 'price' on the right side here is the OLD price, not the just-updated one.

UPDATE ... FROM: Pulling Values From Another Table

Since SQLite 3.33, UPDATE supports a FROM clause for cross-table updates. This is the cleanest way to sync data between tables:

The subquery computes per-customer totals; the outer UPDATE joins those results back into customers on id. Without UPDATE ... FROM you'd be writing a correlated subquery for every column — much noisier.

A few rules to keep in mind:

  • The target table goes after UPDATE, not in the FROM list.
  • The WHERE clause does the join — there's no ON keyword here.
  • If the join could match more than one row in FROM, the result is unspecified. Make sure your join keys produce at most one match per target row.

RETURNING: See What Changed

SQLite (3.35+) lets UPDATE return the modified rows in the same statement. Handy when your application needs the post-update values without a follow-up SELECT:

You get back the rows that were actually touched, with their new values. Saves a round-trip and removes a class of race conditions in concurrent code. There's a whole page on RETURNING later in this chapter.

UPDATE OR REPLACE: Handling Constraint Conflicts

If your update would violate a UNIQUE constraint, the default behavior is to abort the statement with an error. The OR clause lets you pick a different policy:

The options are OR ABORT (default), OR REPLACE, OR IGNORE, OR FAIL, and OR ROLLBACK. REPLACE is the dangerous one — it deletes the conflicting row, which can cascade through foreign keys. Use it only when you genuinely mean "if there's already a row with this unique value, throw it away."

For most upsert-style work, the dedicated INSERT ... ON CONFLICT syntax is clearer. There's a page on that.

Wrap Risky Updates in a Transaction

When you're modifying a lot of rows or running multiple UPDATE statements that need to succeed together, wrap them in a transaction. If anything goes wrong, you can roll back to the state before:

If the second statement fails (say, a constraint kicks in), ROLLBACK undoes the first. Without a transaction, you'd be left with a half-finished transfer — Ada down 25, Boris unchanged. Transactions get their own chapter later; just know they exist and that bulk updates almost always belong inside one.

Common Pitfalls

A short list of things that bite people:

  • Forgetting WHERE — updates every row. Read your statement out loud before running it.
  • Wrong operator in WHEREWHERE status = NULL matches nothing. Use IS NULL. We'll cover this in the operators page.
  • Updating with a subquery that returns more than one row when you expect one. Use LIMIT 1 or aggregate the subquery, or you'll get errors or surprising results.
  • Confusing UPDATE OR REPLACE with UPSERT. OR REPLACE deletes conflicting rows. INSERT ... ON CONFLICT DO UPDATE modifies them in place. Different operations.

Next: DELETE

UPDATE modifies rows; DELETE removes them. The same WHERE discipline applies — and the same "run a SELECT first" habit will save you from the same kinds of disasters. That's the next page.

Frequently Asked Questions

What is the basic syntax of UPDATE in SQLite?

UPDATE table_name SET column = value WHERE condition;. The SET clause lists the columns you want to change and their new values. The WHERE clause picks which rows get changed — leave it off and every row in the table gets updated.

How do I update multiple columns in one statement?

Separate the assignments with commas inside the SET clause: UPDATE users SET name = 'Ada', email = 'ada@x.com' WHERE id = 1;. One statement, one trip to the database, one row updated. Don't repeat SET for each column.

Can SQLite update a table from another table?

Yes — UPDATE ... FROM (added in SQLite 3.33) lets you join another table or subquery into the update. You write UPDATE target SET col = source.col FROM source WHERE target.id = source.id;. It's the cleanest way to copy values across tables.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED