SQLite and unique rowids ... Something you really need to know...
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 (I was part of the group until some time ago). As always a simple example worths more than 1000 words in my bad English :-)
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 the query SELECT rowid,* FROM test;
Here it is the result:
1 marco
2 giuly
3 gregory
4 house
Everything is fine until this point...
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.
Special thanks to Mike Bailey for pointed out this issue.
If you have some time then read on...
A lot of people don't realize that a rowid can change (I was part of the group until some time ago). As always a simple example worths more than 1000 words in my bad English :-)
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 the query SELECT rowid,* FROM test;
Here it is the result:
1 marco
2 giuly
3 gregory
4 house
Everything is fine until this point...
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.
Special thanks to Mike Bailey for pointed out this issue.


4 Comments:
It is probably better behavour to always explicitly define your own integer keys rather than rely on the DB specific implementation of a 'rowid'
This will help make your db schema more portable.
For eg Sybase doesn't have the rowID concept.
Gerard
By Anonymous, at 2:40 AM
This is the same for Oracle which also has a ROWID column. Oracle's ROWID is also not guaranteed to change and may do so at any time. Using ROWID as data keys is bad architecture.
By Anonymous, at 5:14 PM
but then it will need to create an internal index on the primary key, right. The beauty of the rowid is there is no index on it, it is like a pointer. If it only gets lost during vaccuum I can live with that,but if it can truly change anytime, then I guess I will have to do what you suggest.
By Ben Bryant, at 10:31 PM
Holy crap! i wish i had known about this a long time ago!
Note that rowids can also change when you use REPLACE INTO (or ON CONFLICT REPLACE) and overwrite a record's unique key - the old record is deleted and a new record (with new rowid) is inserted. This also happens when you use custom AUTOINCREMENT PRIMARY KEY fields, though.
By s5n, at 10:47 AM
Post a Comment
<< Home