UPDATE
Core statement
Change column values on rows that already exist with a standard SQL UPDATE statement.

Web SQL Database is a deprecated browser API that stores structured data in a local SQLite database. The SQL UPDATE statement changes existing rows—user profiles, settings, cart quantities, or sync flags—without deleting and re-inserting them. This tutorial covers UPDATE syntax, targeting rows with WHERE, listing columns with SET, binding safe ? parameters, checking rowsAffected, handling errors, five worked examples, and why Web SQL is deprecated in favor of IndexedDB.
Core statement
Change column values on rows that already exist with a standard SQL UPDATE statement.
New values
List one or more column = value pairs to change—untouched columns keep their data.
Target rows
Filter exactly which rows change—omit it and the whole table is updated.
Safe params
Bind new values and ids with ? placeholders instead of concatenating SQL.
Verify change
Confirm how many rows actually changed—zero means no match, not necessarily an error.
Atomic writes
Every executeSql call runs inside db.transaction().
Web SQL Database is a deprecated browser API for client-side relational storage. It uses SQLite under the hood, so standard SQL statements—including UPDATE—work just like they do on server-side databases.
The W3C deprecated Web SQL in favor of IndexedDB, and Chrome removed it in version 97. Although the API is no longer recommended for new projects, understanding UPDATE still helps you maintain legacy applications and grasp the SQL fundamentals that carry over to other databases.
Data rarely stays static—users edit profiles, toggle settings, or an app marks a row as synced. UPDATE is the only way to change data in place in a SQL database; done carelessly (missing a WHERE, ignoring rowsAffected) it is also an easy way to overwrite data you meant to keep untouched.
Modifies existing columns without deleting or re-inserting the row.
Always target rows with WHERE—without it, every row is updated.
? placeholders keep new values and ids safe from SQL injection.
Web SQL is educational for legacy code—use IndexedDB for new work.
In short: UPDATE table SET col = ? WHERE condition, bound with ?, inside a transaction, confirmed with rowsAffected—that pattern changes rows safely in Web SQL and in most SQL databases.
Before updating, open the database and make sure the table exists. Seed a starter row with INSERT OR IGNORE so there is something to update in every example below.
const db = openDatabase('myDatabase', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)'
);
tx.executeSql(
'INSERT OR IGNORE INTO users (id, name, age) VALUES (?, ?, ?)',
[1, 'John Doe', 25]
);
}); INSERT OR IGNORE adds the starter row only if id 1 does not exist yet—handy for demos and first-run setup, and it means re-running this snippet never throws a duplicate-key error.
Standard SQL syntax for modifying existing rows:
UPDATE table_name
SET column1 = value1, column2 = value2
WHERE condition; In Web SQL, call it through executeSql with bound parameters:
tx.executeSql(
'UPDATE users SET name = ?, age = ? WHERE id = ?',
[newName, newAge, id],
function (tx, result) { /* success */ },
function (tx, error) { /* failure */ }
); | Argument | Description |
|---|---|
sqlStatement | The UPDATE ... SET ... WHERE ... string, with ? placeholders for dynamic values. |
arguments | Array of values bound to each ?, in order—e.g. [newName, newAge, id]. |
successCallback (optional) | Called as (tx, result); inspect result.rowsAffected. |
errorCallback (optional) | Called as (tx, error); return true to roll back the transaction. |
WHERE when updating specific rows—omitting it updates every row in the table.SET—untouched columns keep their existing values.? — never concatenate user input into the SQL string.result.rowsAffected — zero means no row matched (wrong id or missing record).| Operation | Code pattern |
|---|---|
| Update one row | UPDATE t SET col = ? WHERE id = ? |
| Update multiple columns | SET name = ?, age = ? WHERE id = ? |
| Verify success | result.rowsAffected > 0 |
| No match | rowsAffected === 0 — row not found |
| Update all rows | UPDATE t SET status = ? (no WHERE — use carefully) |
WHERE id = ?One row
SET name = ?, age = ?New data
rowsAffectedConfirm hit
db.transaction()Required
All three change what a table holds—but they disagree on what happens to the row itself.
edits rowsChanges only the columns you list in SET—other columns and the row itself stay intact.
overwrites rowDeletes the whole existing row with the same key, then inserts a brand-new one—every column must be supplied again.
removes rowsDrops matching rows entirely—use it when data should disappear, not change.
See the full INSERT tutorial for creating new rows and DELETE tutorial for removing them instead of editing in place.
Reach for UPDATE whenever a row already exists and only some of its data needs to change.
The user changes their display name, bio, or avatar—update that one row by id.
Toggle theme, language, or notification flags and save the new value with UPDATE.
Mark a row as “sent to server” after a background upload succeeds.
Increase or decrease a cart item’s qty column when the user changes it.
UPDATE silently changes zero rows if the id is missing—use INSERT first, or INSERT OR REPLACE for an upsert.
Key benefit: a precise SET list plus a targeted WHERE clause changes exactly the fields you intend—nothing more, nothing less.
The UPDATE statement modifies columns on rows that match your WHERE condition. Wrap the logic in a reusable function:
function updateRecord(id, newName, newAge) {
db.transaction(function (tx) {
tx.executeSql(
'UPDATE users SET name = ?, age = ? WHERE id = ?',
[newName, newAge, id],
function (tx, result) {
console.log('Rows updated:', result.rowsAffected);
},
function (tx, error) {
console.error('Update error:', error.message);
return true;
}
);
});
}
updateRecord(1, 'Jane Doe', 26); openDatabase — opens or creates the Web SQL database.transaction — wraps the update in an atomic unit.executeSql — runs UPDATE ... SET ... WHERE id = ? with bound parameters.This updates the name and age columns for the user with id = 1—every other column on that row is left untouched.
Updates can “succeed” with rowsAffected === 0 when no row matches—that is not a SQL error, just a miss. Always inspect rowsAffected in the success callback and handle real SQL errors in the error callback.
tx.executeSql(
'UPDATE users SET name = ?, age = ? WHERE id = ?',
[newName, newAge, id],
function (tx, result) {
if (result.rowsAffected === 0) {
console.warn('No records were updated — check the id.');
} else {
console.log('Record updated successfully.');
}
},
function (tx, error) {
console.error('Update error:', error.message);
return true;
}
); rowsAffected === 0 — the query ran but matched no rows (wrong id, or row was never inserted).true from the error callback to roll back the transaction.These examples use the Web SQL API pattern. Use the Try It Yourself links to run live demos. Web SQL works only in browsers that still expose openDatabase; otherwise the demo shows a clear status message.
Update a single row by id with bound parameters, then wrap the pattern in a reusable function.
Change name and age for user id 1.
const db = openDatabase('myDatabase', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)');
tx.executeSql('INSERT OR IGNORE INTO users (id, name, age) VALUES (?, ?, ?)', [1, 'John Doe', 25]);
tx.executeSql(
'UPDATE users SET name = ?, age = ? WHERE id = ?',
['Jane Doe', 26, 1],
function (tx, result) {
console.log('Updated rows:', result.rowsAffected);
},
function (tx, error) {
console.error('Error:', error.message);
}
);
}); The transaction creates the table, seeds John Doe, then updates that row to Jane Doe age 26. rowsAffected returns 1 when exactly one row changed.
Call the same function from buttons, forms, or sync handlers.
function updateRecord(id, newName, newAge) {
db.transaction(function (tx) {
tx.executeSql(
'UPDATE users SET name = ?, age = ? WHERE id = ?',
[newName, newAge, id],
function (tx, result) {
console.log('Updated', result.rowsAffected, 'row(s) for id', id);
},
function (tx, error) {
console.error('Update error:', error.message);
return true;
}
);
});
}
updateRecord(1, 'Jane Doe', 26);
updateRecord(2, 'Alex Kim', 30); /* id 2 does not exist */ The second call returns 0 rows if id 2 was never inserted—a signal to insert first or show “user not found” rather than assuming success.
Detect missing rows, bind form values, and build a complete demo page.
Use rowsAffected to warn when the target id does not exist.
function updateUser(id, name) {
db.transaction(function (tx) {
tx.executeSql(
'UPDATE users SET name = ? WHERE id = ?',
[name, id],
function (tx, result) {
if (result.rowsAffected === 0) {
console.warn('No user with id', id);
} else {
console.log('Name updated for id', id);
}
}
);
});
}
updateUser(99, 'Ghost User'); /* id 99 does not exist */ Unlike a SQL error, updating a missing id succeeds with rowsAffected === 0. Your app should treat that as “not found” rather than success.
Read values from input fields and bind them to the UPDATE query.
document.getElementById('saveBtn').addEventListener('click', function () {
const name = document.getElementById('nameInput').value.trim();
const age = parseInt(document.getElementById('ageInput').value, 10);
if (!name || isNaN(age)) return;
db.transaction(function (tx) {
tx.executeSql(
'UPDATE users SET name = ?, age = ? WHERE id = ?',
[name, age, 1],
function (tx, result) {
alert(result.rowsAffected ? 'Saved!' : 'User not found.');
}
);
});
}); Validate input in JavaScript first, then pass clean values through ? bindings. Never build SQL like "UPDATE ... SET name = '" + name + "'".
Insert a record, then update it with a second button—matching the classic Web SQL workflow.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Web SQL Update Example</title>
</head>
<body>
<h1>Web SQL Update Example</h1>
<button type="button" id="addRecord">Add Record</button>
<button type="button" id="updateRecord">Update Record</button>
<p id="status"></p>
<script>
if (!window.openDatabase) {
document.getElementById('status').textContent =
'Web SQL is not supported in this browser.';
} else {
const db = openDatabase('myDatabase', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)'
);
});
document.getElementById('addRecord').addEventListener('click', function () {
db.transaction(function (tx) {
tx.executeSql(
'INSERT OR REPLACE INTO users (id, name, age) VALUES (?, ?, ?)',
[1, 'John Doe', 25],
function () {
document.getElementById('status').textContent = 'Added John Doe';
}
);
});
});
document.getElementById('updateRecord').addEventListener('click', function () {
updateRecord(1, 'Jane Doe', 26);
});
function updateRecord(id, newName, newAge) {
db.transaction(function (tx) {
tx.executeSql(
'UPDATE users SET name = ?, age = ? WHERE id = ?',
[newName, newAge, id],
function (tx, result) {
document.getElementById('status').textContent =
result.rowsAffected
? 'Updated to ' + newName
: 'No row found — add a record first';
},
function (tx, error) {
document.getElementById('status').textContent = 'Error: ' + error.message;
return true;
}
);
});
}
}
</script>
</body>
</html> Click Add Record to seed id 1, then Update Record changes name and age. Status text on the page gives immediate feedback either way.
Real-world scenarios where changing an existing row is exactly what you need.
Update display name, bio, or avatar URL fields when a user edits their account.
Example: UPDATE users SET name = ? WHERE id = ?.
Persist theme, font size, or language preferences the user changes locally.
Example: UPDATE settings SET theme = ? WHERE user_id = ?.
Set synced = 1 after successfully uploading a locally-created row to a server.
Example: UPDATE queue SET synced = 1 WHERE id = ?.
Adjust qty when a shopper increases or decreases how many items they want.
Example: UPDATE cart SET qty = ? WHERE product_id = ?.
Overwrite a stale cached value with fresh data instead of deleting and re-inserting the row.
Example: UPDATE cache SET value = ?, updated_at = ? WHERE key = ?.
Patch existing Web SQL data in older mobile web apps still running in the wild.
Example: a support script correcting bad values in an old dataset.
Pro Tip: pair every update with a SELECT during development so you can confirm the row landed with the values you expected.
Why the standard SQL UPDATE pattern is worth learning, even in a deprecated API.
WHERE changes exactly the rows you specify—nothing implicit.
? bindings sanitize new values automatically, avoiding SQL injection.
rowsAffected tells you exactly how many rows changed—no guessing.
Wrapped in db.transaction(), related statements succeed or fail together.
Pro Tip: this exact pattern—WHERE, a minimal SET list, bound parameters, and checking affected rows—transfers directly to IndexedDB, SQLite, and server-side SQL.
Follow these practices to write safe, predictable updates.
Run the equivalent SELECT ... WHERE ... to confirm which rows will change before you update.
Zero means no match—update your UI to say “not found,” not “saved.”
Use ? placeholders for new values and ids—never build SQL with string concatenation.
Keep the SET clause short—every extra column is one more thing that could overwrite good data by mistake.
Web SQL is deprecated—treat new features as an opportunity to move to IndexedDB.
Pro Tip: log every update’s SQL, bound values, and rowsAffected during development—it turns “why didn’t that save?” bugs into a quick log lookup.
Avoid these mistakes when changing rows with Web SQL.
Forgetting the condition changes every row in the table instantly, with no confirmation.
→ Always double-check for a WHERE clause before running an update.
Building queries with string concatenation opens the door to SQL injection.
→ Bind every dynamic value with ? placeholders instead.
Treating every callback as success hides “row not found” cases from your users.
→ Check result.rowsAffected and branch your UI message accordingly.
UPDATE only changes columns you list and does nothing if the row is missing; INSERT OR REPLACE deletes and recreates the entire row, resetting any column you forget to supply.
→ Use UPDATE to edit specific fields on a known row, and INSERT OR REPLACE only for full-row upserts.
Chrome removed Web SQL in version 97—code that assumes openDatabase exists will crash.
→ Feature-detect with if (window.openDatabase) before running any Web SQL code.
Pro Tip: when in doubt, run the same condition as a SELECT first—if the preview looks right, the update will too.
WHERE id = ? selects matching rows.
SET name = ?, age = ? assigns columns.
executeSql writes the change; the transaction commits it.
rowsAffected tells you how many rows changed.
WHERE unless you intentionally mean to update every row.rowsAffected—zero means no match, not necessarily an error.? placeholders—never string-concatenate SQL.Quick Takeaway: Web SQL is deprecated—practice UPDATE here to learn the pattern, then apply the same WHERE + bindings + rowsAffected habits in IndexedDB and other SQL databases.
Web SQL was never implemented in Firefox or Internet Explorer. Chrome and other Chromium browsers removed it in Chrome 97. Only older Safari versions historically supported it. Feature-detect with window.openDatabase before running any demo or legacy code.
Web SQL is not part of any current web standard. Modern Chrome, Edge, and Opera have removed it entirely; Firefox never implemented it. Treat this tutorial as educational for legacy maintenance only.
Bottom line: Do not build new features on Web SQL. For cross-browser client-side storage today, use IndexedDB.
Updating records with Web SQL means running UPDATE ... SET ... WHERE ... inside db.transaction, binding values safely with ?, and checking rowsAffected to confirm the right row changed.
You have now covered the full Web SQL CRUD series—INSERT, SELECT, UPDATE, and DELETE. Although Web SQL is deprecated, the same patterns carry forward directly into IndexedDB or a server-side database.
Practice the five examples above, then continue to Web Workers to run scripts off the main thread.
WHERE to target specific rows? placeholdersresult.rowsAffected after every updatetrue to roll backWHERE unless you mean to update all rowsrowsAffected is 0Use these points when modifying rows in a client-side database.
Change rows.
BasicsTarget id.
FilterSafe params.
SecurityVerify hit.
ReliabilityUse IndexedDB.
ModernUPDATE table_name SET col = ? without a WHERE clause changes every row in the table—the SET list decides which columns change, and rowsAffected is the only way to confirm how many rows actually did. Because Web SQL is deprecated, treat every UPDATE you write here as a rehearsal for the same pattern in IndexedDB.
Now that you can create, read, update, and delete rows, learn how to keep heavy work off the main thread.
9 people found this page helpful