DELETE
Core statement
Remove rows from a table with a standard SQL DELETE FROM statement.

Web SQL Database is a deprecated browser API that stores structured data in a local SQLite database. The SQL DELETE statement removes rows you no longer need—cleared cart items, revoked sessions, or outdated cache entries. This tutorial covers DELETE syntax, targeting rows with WHERE, binding safe parameters, checking rowsAffected, handling errors, five worked examples, and why Web SQL is deprecated in favor of IndexedDB.
Core statement
Remove rows from a table with a standard SQL DELETE FROM statement.
Target rows
Filter exactly which rows are removed—omit it and the whole table empties.
Safe params
Bind ids and values with ? placeholders instead of concatenating SQL.
Verify removal
Confirm how many rows were actually deleted—zero means no match.
Handle failure
Catch SQL errors in the failure callback and roll back safely.
Atomic ops
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 DELETE—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 DELETE still helps you maintain legacy applications and grasp the SQL fundamentals that carry over to other databases.
Every app eventually needs to remove data—a cart item, a stale cache row, a logged-out session. DELETE is the only way to do that in a SQL database, but done carelessly it is also the easiest way to destroy data you meant to keep.
Permanently deletes matching rows from a table—there is no built-in undo.
Always target rows with WHERE—without it, the entire table empties.
? placeholders keep dynamic values safe from SQL injection.
Web SQL is educational for legacy code—use IndexedDB for new work.
In short: DELETE FROM table WHERE condition, bound with ?, inside a transaction, checked with rowsAffected—that pattern removes rows safely in Web SQL and in most SQL databases.
Before deleting records, know which table and columns hold your data. A clear schema means your WHERE clause targets the correct rows.
const db = openDatabase('myDatabase', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql(
'CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT)'
);
tx.executeSql(
'INSERT OR IGNORE INTO items (id, name) VALUES (?, ?)',
[1, 'Sample Record']
);
}); This creates an items table with id and name, then seeds one row so you have something to delete in the examples below.
Standard SQL syntax for removing rows:
DELETE FROM table_name WHERE condition; In Web SQL, call it through executeSql with bound parameters:
tx.executeSql(
'DELETE FROM items WHERE id = ?',
[id],
function (tx, result) { /* success */ },
function (tx, error) { /* failure */ }
); | Argument | Description |
|---|---|
sqlStatement | The DELETE FROM ... WHERE ... string, with ? placeholders for dynamic values. |
arguments | Array of values bound to each ?, in order—e.g. [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 deleting specific rows—without it, every row in the table is removed.? — never concatenate user input into the SQL string.result.rowsAffected — zero means no row matched.| Operation | Code pattern |
|---|---|
| Delete one row | DELETE FROM t WHERE id = ? |
| Delete by name | DELETE FROM t WHERE name = ? |
| Verify success | result.rowsAffected > 0 |
| No match | rowsAffected === 0 — row not found |
| Delete all rows | DELETE FROM t (no WHERE — dangerous) |
WHERE id = ?One row
[id]? binding
rowsAffectedConfirm hit
db.transaction()Required
All three change existing data—but they solve different problems.
removes rowsDrops matching rows entirely—the row and its data are gone.
edits rowsKeeps the row but changes column values—use when data should stay, just change.
DELETE FROM tNo WHERE empties the whole table but keeps its schema—rarely what you want by accident.
See the full UPDATE tutorial when you need to modify rows instead of removing them.
Reach for DELETE whenever data should genuinely disappear, not just change.
The shopper clicks “remove”—delete that row by id, not the whole cart.
Wipe session or token rows on sign-out so stale credentials cannot be reused.
Delete rows older than a timestamp, or discard unsaved drafts the user abandoned.
Clear all completed tasks or all rows matching a status with one WHERE clause.
Never run DELETE FROM table_name without a condition unless you truly mean to empty it.
Key benefit: a precise WHERE clause removes exactly the rows you intend—nothing more, nothing less.
The DELETE statement removes rows that match your WHERE condition. Wrap the logic in a reusable function:
function deleteRecord(id) {
db.transaction(function (tx) {
tx.executeSql(
'DELETE FROM items WHERE id = ?',
[id],
function (tx, result) {
console.log('Deleted rows:', result.rowsAffected);
},
function (tx, error) {
console.error('Delete error:', error.message);
return true;
}
);
});
}
deleteRecord(1); openDatabase — opens or creates the Web SQL database.transaction — wraps the delete in an atomic unit.executeSql — runs DELETE FROM ... WHERE id = ? with bound parameters.Errors can come from invalid SQL, missing tables, or constraint issues. A delete can also “succeed” with rowsAffected === 0 when no row matched—treat that separately from a real error.
tx.executeSql(
'DELETE FROM items WHERE id = ?',
[id],
function (tx, result) {
if (result.rowsAffected === 0) {
console.warn('No row deleted — id may not exist.');
} else {
console.log('Record deleted successfully.');
}
},
function (tx, error) {
console.error('Error deleting record:', error.message);
return true;
}
); 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.
Delete a single row by id with bound parameters.
Remove the item with id = 1 from the items table.
const db = openDatabase('myDatabase', '1.0', 'Test DB', 2 * 1024 * 1024);
db.transaction(function (tx) {
tx.executeSql('CREATE TABLE IF NOT EXISTS items (id INTEGER PRIMARY KEY, name TEXT)');
tx.executeSql('INSERT OR IGNORE INTO items (id, name) VALUES (?, ?)', [1, 'Sample Record']);
tx.executeSql(
'DELETE FROM items WHERE id = ?',
[1],
function (tx, result) {
console.log('Deleted rows:', result.rowsAffected);
},
function (tx, error) {
console.error('Error:', error.message);
}
);
}); The transaction seeds a row, then deletes it. rowsAffected returns 1 when exactly one row was removed.
Call the same function from buttons, list items, or swipe-to-delete handlers.
function deleteRecord(id) {
db.transaction(function (tx) {
tx.executeSql(
'DELETE FROM items WHERE id = ?',
[id],
function (tx, result) {
console.log('Deleted', result.rowsAffected, 'row(s) for id', id);
},
function (tx, error) {
console.error('Delete error:', error.message);
return true;
}
);
});
}
deleteRecord(1);
deleteRecord(99); /* id 99 does not exist */ The second call returns 0 rows when id 99 was never inserted—not an error, but worth reporting to the user.
Verify deletions, delete by condition, and build a complete demo page.
Use rowsAffected to warn when the target id does not exist.
function deleteItem(id) {
db.transaction(function (tx) {
tx.executeSql(
'DELETE FROM items WHERE id = ?',
[id],
function (tx, result) {
if (result.rowsAffected === 0) {
console.warn('No item with id', id);
} else {
console.log('Removed item', id);
}
}
);
});
}
deleteItem(42); /* does not exist */ Deleting a missing id does not throw an error—it succeeds with zero rows affected. Your UI should distinguish “not found” from “deleted.”
Remove all rows matching a column value—for example, clear completed tasks.
/* table: tasks (id, title, done INTEGER 0/1) */
function deleteCompletedTasks() {
db.transaction(function (tx) {
tx.executeSql(
'DELETE FROM tasks WHERE done = ?',
[1],
function (tx, result) {
console.log('Cleared', result.rowsAffected, 'completed task(s)');
}
);
});
} WHERE done = ? can match multiple rows. rowsAffected reports the total number removed. Double-check your condition before running bulk deletes.
Set up the database, seed a row, and delete it with a button click.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Web SQL Delete Example</title>
</head>
<body>
<h1>Delete Records from Web SQL</h1>
<button type="button" id="deleteBtn">Delete Record with ID 1</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 items (id INTEGER PRIMARY KEY, name TEXT)'
);
tx.executeSql(
'INSERT OR IGNORE INTO items (id, name) VALUES (?, ?)',
[1, 'Sample Record']
);
});
document.getElementById('deleteBtn').addEventListener('click', function () {
deleteRecord(1);
});
function deleteRecord(id) {
db.transaction(function (tx) {
tx.executeSql(
'DELETE FROM items WHERE id = ?',
[id],
function (tx, result) {
document.getElementById('status').textContent =
result.rowsAffected
? 'Deleted id ' + id
: 'No row found for id ' + id;
},
function (tx, error) {
document.getElementById('status').textContent =
'Error: ' + error.message;
return true;
}
);
});
}
}
</script>
</body>
</html> The page seeds id 1 on load. Clicking the button runs deleteRecord(1) and updates the status text on the page.
Real-world scenarios where removing rows is exactly what you need.
Remove products the user removed from their basket.
Example: DELETE FROM cart WHERE product_id = ?.
Discard unsaved notes or form drafts the user chose not to keep.
Example: a “discard draft” button in an editor.
Wipe session or token rows on sign-out for security.
Example: DELETE FROM sessions WHERE user_id = ?.
Delete stale rows older than a timestamp to keep storage fresh.
Example: DELETE FROM cache WHERE expires_at < ?.
Clear every row matching a condition, like all completed tasks.
Example: DELETE FROM tasks WHERE done = 1.
Purge records in older Web SQL–based apps still running in the wild.
Example: a support script cleaning orphaned rows.
Pro Tip: pair every delete with a SELECT during development so you can preview exactly which rows a WHERE clause will match.
Why the standard SQL DELETE pattern is worth learning, even in a deprecated API.
WHERE removes exactly the rows you specify—nothing implicit.
? bindings sanitize 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, bound parameters, transactions, and checking affected rows—transfers directly to IndexedDB, SQLite, and server-side SQL.
Follow these practices to write safe, predictable deletes.
Run the equivalent SELECT ... WHERE ... to confirm which rows will be removed before you delete.
Zero means no match—update your UI to say “not found,” not “deleted.”
Use ? placeholders for ids, names, and conditions—never build SQL with string concatenation.
Ask the user to confirm before running a delete that cannot be undone.
Web SQL is deprecated—treat new features as an opportunity to move to IndexedDB.
Pro Tip: log every delete’s SQL, bound values, and rowsAffected during development—it turns “why did that disappear?” bugs into a quick log lookup.
Avoid these mistakes when removing rows with Web SQL.
Forgetting the condition empties the entire table instantly, with no confirmation.
→ Always double-check for a WHERE clause before running a delete.
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.
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.
Once a transaction commits, deleted rows are gone—there is no built-in recovery.
→ Confirm destructive actions in the UI, or keep a backup before deleting.
Pro Tip: when in doubt, run the same condition as a SELECT first—if the preview looks right, the delete will too.
openDatabase() then db.transaction() starts an atomic unit of work.
WHERE id = ? selects rows to remove.
executeSql removes matches; the transaction commits the change.
rowsAffected reports how many rows were deleted.
WHERE unless you intentionally mean to clear the entire table.rowsAffected—zero means no match, not necessarily an error.? placeholders—never string-concatenate SQL.Quick Takeaway: Web SQL is deprecated—practice DELETE 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.
Deleting records with Web SQL means running DELETE FROM ... WHERE ... inside db.transaction, binding values safely with ?, and checking rowsAffected to confirm the right rows were removed.
Although Web SQL is deprecated, understanding deletes helps you maintain older systems. For new projects, use IndexedDB—but the SQL habits you learned here (safe parameters, WHERE clauses, and row counts) apply everywhere.
Practice the five examples above, then continue to INSERT so you always have fresh rows to delete.
WHERE to target specific rows? placeholdersresult.rowsAffected after every deletetrue to roll backWHERE unless you mean to wipe the tablerowsAffected is 0Use these points when removing rows from a client-side database.
Remove rows.
BasicsTarget id.
FilterSafe params.
SecurityVerify hit.
ReliabilityConfirm first.
SafetyDELETE FROM table_name without a WHERE clause removes every row in the table but keeps the table structure — faster than dropping and recreating the table when you want an empty slate with the same schema. Because Web SQL is deprecated, treat every DELETE you write here as a rehearsal for the same pattern in IndexedDB.
Now that you can remove rows, learn how to add new ones so there is always fresh data to work with.
9 people found this page helpful