Here are 2 ideas. Using an [AFTER INSERT trigger](https://sqlite.org/lang_createtrigger.html) (note the use of `INT PRIMARY KEY` instead of `INTEGER PRIMARY KEY`): ```bash sqlite> CREATE TABLE t1( ...> id INT PRIMARY KEY ...> ); sqlite> sqlite> CREATE TRIGGER t1_id AFTER INSERT ON t1 BEGIN ...> UPDATE t1 SET id = rowid-1 WHERE rowid = new.rowid; ...> END; sqlite> sqlite> INSERT INTO t1 VALUES(NULL); sqlite> INSERT INTO t1 VALUES(NULL); sqlite> INSERT INTO t1 VALUES(NULL); sqlite> sqlite> SELECT * FROM t1; +----+ | id | +----+ | 0 | | 1 | | 2 | +----+ ``` Using [generated columns](https://www.sqlite.org/gencol.html): ```bash sqlite> CREATE TABLE t2( ...> pk INTEGER PRIMARY KEY, ...> id INT GENERATED ALWAYS AS (pk-1) STORED UNIQUE ...> ); sqlite> sqlite> INSERT INTO t2 VALUES(NULL); sqlite> INSERT INTO t2 VALUES(NULL); sqlite> INSERT INTO t2 VALUES(NULL); sqlite> sqlite> SELECT * FROM t2; +----+----+ | pk | id | +----+----+ | 1 | 0 | | 2 | 1 | | 3 | 2 | +----+----+ ```