Quick answer
- In 1bench
- Right-click the table in the sidebar, choose Truncate Table, type TRUNCATE and click Truncate Table.
- In SQL
- sql
DELETE FROM audit_log; DELETE FROM sqlite_sequence WHERE name = 'audit_log';The first statement removes every row. The second resets the AUTOINCREMENT counter so the next row gets id 1; skip it to keep counting from the old maximum.
Truncate a table visually in 1bench
1bench has a Truncate Table action for SQLite tables. Because SQLite has no TRUNCATE, it runs DELETE FROM on the table and then removes the table's row from sqlite_sequence, so the AUTOINCREMENT counter starts over as well.
Prerequisite: download 1bench. Free 7-day trial, no sign-up.
- 1
Open your SQLite file
Connect to your .sqlite or .db file in 1bench and expand it in the sidebar.
- 2
Choose Truncate Table
Right-click the table and choose Truncate Table. Views do not get this item, and on a read-only connection it is greyed out.
- 3
Type TRUNCATE to confirm
The Truncate Table dialog warns that all data in the table will be permanently deleted and that the table structure is kept. The button stays disabled until you type TRUNCATE in the box.
- 4
Run it
Click Truncate Table. 1bench runs DELETE FROM audit_log, then DELETE FROM sqlite_sequence WHERE name = 'audit_log', so the next row you insert gets id 1.
- 5
Check the result
A toast reads Truncated audit_log, and the open grid and the row count in the sidebar refresh to zero. If SQLite refuses, the toast starts with Failed and shows the error.
- 1bench opens SQLite with foreign keys switched on. Emptying a parent table follows each child table's ON DELETE rule: in the demo database, truncating users sets user_id to NULL on all 200 audit_log rows. A child with no ON DELETE action blocks the delete with FOREIGN KEY constraint failed, and nothing is removed.
- DELETE triggers on the table fire once for every row, exactly as they do for a DELETE FROM you type yourself.
- The file does not get smaller. To give the space back to the disk, right-click the connection, choose New Query and run VACUUM.
Truncate a table with SQL
There is no TRUNCATE in SQLite. Both and stop at the parser, so nothing is deleted:
Parse error near line 1: near "TRUNCATE": syntax error
TRUNCATE TABLE audit_log;
^--- error here
The examples below use the 1bench demo database: , (with a foreign key to ), and , all with . Every statement was run on SQLite 3.43.2 and 3.54.1 with the same results; only the CLI's error prefix differs, as noted where it shows up.
Delete all rows with DELETE FROM
A with no clause empties the table and keeps its columns, indexes and triggers.
DELETE FROM audit_log;
SQLite runs this as a truncate behind the scenes. Instead of visiting each row, it clears the table's pages in one step, which shows as a single opcode per table and index. The row count is still reported correctly: the CLI's prints for the demo table.
The fast path is skipped, and rows are deleted one at a time, when any of these is true:
| Condition | Why it matters |
|---|---|
| A clause, even | SQLite has to test each row |
| A clause | Each deleted row has to be returned |
| A trigger on the table | The trigger fires once per row ( and triggers do not count) |
| and the table is a parent or child in a foreign key | Each row has to be checked against the other table |
The result is the same either way. Only the speed changes, which you notice on tables with millions of rows.
Delete all rows and reset the id
does not reset an AUTOINCREMENT counter. SQLite keeps the highest id it has handed out in the table, so after emptying the next insert still gets id 201.
Example: empty the table, then remove its counter so numbering starts again at 1.
DELETE FROM audit_log;
DELETE FROM sqlite_sequence WHERE name = 'audit_log';
INSERT INTO audit_log (action, entity_type) VALUES ('login', 'user');
SELECT id FROM audit_log; -- 1
To start from a number of your choice, update the row instead. The next insert gets .
UPDATE sqlite_sequence SET seq = 1000 WHERE name = 'audit_log';
resets the counter of every table at once. The table itself only exists once some table has used AUTOINCREMENT, and querying it before that fails with "no such table: sqlite_sequence".
Tables without AUTOINCREMENT
A plain has no counter to reset. SQLite picks the largest id in the table plus one, so an empty table starts again at 1 by itself, and the id of a deleted last row is handed out again.
Example: the id 3 comes back after its row is deleted, and the table restarts at 1 once it is empty.
CREATE TABLE notes (id INTEGER PRIMARY KEY, body TEXT);
INSERT INTO notes (body) VALUES ('a'), ('b'), ('c');
DELETE FROM notes WHERE id = 3;
INSERT INTO notes (body) VALUES ('d'); -- gets id 3 again
DELETE FROM notes;
INSERT INTO notes (body) VALUES ('e'); -- gets id 1
That reuse is the reason AUTOINCREMENT exists. Use it when an old id must never point at a new row, for example when ids appear in URLs or logs.
Foreign keys and PRAGMA foreign_keys
Foreign keys are off by default in the sqlite3 CLI and in most drivers ( returns 0), and the setting lasts only for the current connection. With them off, emptying a parent table leaves orphaned child rows behind and no error is raised.
Switch them on first, and the child table's rule decides what happens:
PRAGMA foreign_keys = ON;
DELETE FROM users;
In the demo database is , so the delete succeeds and all 200 log rows lose their user. A child table with no action blocks it instead, and no rows are removed:
Error near line 2: FOREIGN KEY constraint failed
SQLite 3.43 prints the same message as "Runtime error near line 2: FOREIGN KEY constraint failed (19)". lists any orphaned rows left over from a delete you ran with foreign keys off. Note that does nothing inside an open transaction, so set it before .
Shrink the file with VACUUM
Deleting rows does not make the database file smaller. The freed pages go on a free list for SQLite to reuse. In testing, a demo file grown to 10.6 MB stayed at 10.6 MB after , with 2,573 of its 2,586 pages free.
PRAGMA freelist_count; -- pages a VACUUM would give back
VACUUM;
rebuilds the file, here from 10.6 MB down to 53 KB. It needs exclusive access and up to twice the file's size in free disk space while it runs. writes the compacted copy to a new file and leaves the original alone, which also works as a quick backup.
VACUUM INTO 'demo-compact.sqlite';
To have SQLite shrink the file after every delete, turn on auto-vacuum. On an existing database the setting only takes effect after one full .
PRAGMA auto_vacuum = FULL;
VACUUM;
Drop and recreate the table
Dropping the table removes its rows, its indexes, its triggers and its row in one statement, so the counter starts at 1 when you recreate it. Copy the statements first with in the CLI, because they are gone afterwards.
DROP TABLE feature_rollout;
CREATE TABLE feature_rollout (
id INTEGER PRIMARY KEY AUTOINCREMENT,
feature_key TEXT NOT NULL,
enabled INTEGER DEFAULT 0,
rollout_percentage REAL DEFAULT 0 CHECK (rollout_percentage BETWEEN 0 AND 100),
target_countries TEXT,
created_at TEXT DEFAULT (datetime('now')),
updated_at TEXT DEFAULT (datetime('now')),
CHECK (enabled IN (0, 1))
);
The trigger is dropped with the table and has to be created again too. is the safer choice unless you also want to change the table's definition.
Empty every table
SQLite has no single command to truncate all tables. Generate one per table from , skipping SQLite's own tables:
SELECT 'DELETE FROM "' || name || '";'
FROM sqlite_schema
WHERE type = 'table' AND name NOT LIKE 'sqlite_%';
Example: save the output to a file, then run it in one transaction with foreign keys off, so the order of the tables does not matter, and finish with a reset of every counter and a .
PRAGMA foreign_keys = OFF;
BEGIN;
DELETE FROM "users";
DELETE FROM "app_settings";
DELETE FROM "migrations";
DELETE FROM "audit_log";
DELETE FROM "feature_rollout";
DELETE FROM sqlite_sequence;
COMMIT;
PRAGMA foreign_keys = ON;
VACUUM;
If you would rather start from an empty file, copy just the schema with . Without the copy stops on "object name reserved for internal use: sqlite_sequence".
From Python
Python's built-in module runs the same SQL. Pass the table name as a parameter in the query, and keep outside the block, since it cannot run inside a transaction.
import sqlite3
con = sqlite3.connect("demo.sqlite")
con.execute("PRAGMA foreign_keys = ON")
with con:
con.execute("DELETE FROM audit_log")
con.execute("DELETE FROM sqlite_sequence WHERE name = ?", ("audit_log",))
con.execute("VACUUM")
con.close()
TRUNCATE in SQLite PRAGMAs
TRUNCATE does appear in SQLite, but only for journal files. copies the write-ahead log into the database and cuts the file to zero bytes (2.7 MB down to 0 in testing). makes SQLite empty the rollback journal after each transaction instead of deleting it.
PRAGMA wal_checkpoint(TRUNCATE);
PRAGMA journal_mode = TRUNCATE;
Neither one removes any rows from your tables.