SQLite and unique rowid … Something you really need to know.

December 21st, 2010 | 12 Comments »

I posted this article in my old blog on Sunday, January 21, 2007 but I think it’s so important that I decided to re-post it again here.

If you don’t want to read the whole post then just do this: Every time you create a table with sqlite make sure to have an INTEGER PRIMARY KEY AUTOINCREMENT column (the rowid column will be an alias to this one).

If you have some time then read on…

A lot of people don’t realize that a rowid can change. As always a simple example worths more than 1000 words. You can test this example with SQLiteManager.

Create a table without a primary key:
CREATE TABLE test (name TEXT);

Insert some data into the table:
INSERT INTO test (name) VALUES (‘marco’);
INSERT INTO test (name) VALUES (‘giuly’);
INSERT INTO test (name) VALUES (‘gregory’);
INSERT INTO test (name) VALUES (‘house’);

Perform a SELECT rowid,* FROM test;
Here you go the result:
1 marco
2 giuly
3 gregory
4 house

Everything seems OK (until now…)
Now delete a couple of rows:
DELETE FROM test WHERE name=’marco’;
DELETE FROM test WHERE name=’gregory’;

Now perform again: SELECT rowid,* FROM test;
Here it is the result:
2 giuly
4 house

Everything is fine, no?
That’s cool…

Now, perform a VACUUM on the database and run again the query:
SELECT rowid,* FROM test;
Here it is the result:
1 giuly
2 house

Rowids are changed!!!! So please take extra care when you define a table and need to reference records using rowids.
From the official documentation: “Rowids can change at any time and without notice. If you need to depend on your rowid, make it an INTEGER PRIMARY KEY, then it is guaranteed not to change”. And I add also AUTOINCREMENT so you are sure that the same rowid(s) are not reused when rows are deleted.

12 Responses to “SQLite and unique rowid … Something you really need to know.”

  • lux says:

    you dont need to write AUTOINCREMENT in sqlite because a primary key already INCREMENTs by standart.

  • marco says:

    This is not true. If you delete some rows and then VACUUM the database then sqlite will reuse some of the delete rowid values. So you’ll lost uniqueness if you don’t add the AUTOINCREMENT constraint.

  • Naim says:

    RowID isn’t a PRIMARY KEY. PRIMARY KEYs don’t change.!

  • shade says:

    I’m new to sqlite, but I did small experiment and instead

    CREATE TABLE test (name TEXT);

    i created table:


    after adding UNIQUE rowid do not change after doing VACUUM. As you can see I don’t have INTEGER PRIMARY KEY in my schema, but it works. So why does it behave like INTEGER PRIMARY KEY?

  • Siva says:

    Everything is understandable? Thanks for that.
    But, VACUUM means?

  • meneo says:

    Hello, Marco!
    Thx for you post.
    But I have met the problem…
    Table created:

    Also I have
    CREATE UNIQUE INDEX “MainIndex_Match” ON “matches” (“League” ASC, “Match” ASC)

    So. when I do several times
    INSERT OR REPLACE INTO matches (League,Match) VALUES (“Test”,”Test”)
    Replace changes my MatchID… 🙁 Why? Can I avoid it?

    Thank you

  • William says:

    I can’t find any SQLite documentation page that contains the quoted text about ROWID values changing at any time and without notice.

    At the lang_vacuum page (linked above), there’s this:

    “The VACUUM command may change the ROWIDs of entries in any tables that do not have an explicit INTEGER PRIMARY KEY.”

    That seems to be the only mention anywhere of ROWID values changing.

    Where is the documentation page that contains the text you quoted?

  • Pero says:

    If you assign a field such as (id INTEGER PRIMARY KEY) – this field will become an alias for ROWID but ROWID will not change. So only if you don’t have an alias for ROWID (such as “id” field in the table) which is by-the-way the usual way of using SQL tables – only then ROWID will change.

  • Pero says:

    AUTOINCREMENT doesn’t have anything to do with row id uniqueness. It has to do with reusing of ID value.

    AUTOINCREMENT only serves to make sure you generate new and unused id for the new row.

    if you create a row with ID 123 and then delete it, without AUTOINCREMENT it may be reused so if you insert again ID 123 may be used again at later time. With AUTOINCREMENT – it won’t.

    It will use different ID (that has ever before existed in that same table).

    AUTOINCREMENT also won’t touch anything which already existed so if you delete ID 123 and then add it again with the same ID, AUTOINCREMENT won’t change – it only changes when you add higher value ID than has existed previously in the table.

  • Regarding AUTOINCREMENT, straight from the SQLite documentation (@https://sqlite.org/autoinc.html)”:

    “1. The AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and should be avoided if not strictly needed. It is usually not needed.”

  • Tobi says:

    You should really change this post. The comment section explained already that this is wrong, AUTOINCREMENT keyword imposes extra CPU, memory, disk space, and disk I/O overhead and the ROWID does not change when you specify an INTEGER PRIMARY KEY field. Only if you don’t.

Leave a Reply

This field is required

This field is required