Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLite insert or ignore and return original _rowid_

Tags:

I've spent some time reading the SQLite docs, various questions and answers here on Stack Overflow, and this thing, but have not come to a full answer.

I know that there is no way to do something like INSERT OR IGNORE INTO foo VALUES(...) with SQLite and get back the rowid of the original row, and that the closest to it would be INSERT OR REPLACE but that deletes the entire row and inserts a new row and thus gets a new rowid.

Example table:

CREATE TABLE foo(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    data TEXT
);

Right now I can do:

sql = sqlite3.connect(":memory:")
# create database
sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);", ("Some text.", ))
the_id_of_the_row = None
for row in sql.execute("SELECT id FROM foo WHERE data = ?", ("Some text.", )):
    the_id_of_the_row = row[0]

But something ideal would look like:

the_id_of_the_row = sql.execute("INSERT OR IGNORE foo(data) VALUES(?)", ("Some text", )).lastrowid

What is the best (read: most efficient) way to insert a row into a table and return the rowid, or to ignore the row if it already exists and just get the rowid? Efficiency is important because this will be happening quite often.

Is there a way to INSERT OR IGNORE and return the rowid of the row that the ignored row was compared to? This would be great, as it would be just as efficient as an insert.

like image 875
Whymarrh Avatar asked Nov 06 '12 04:11

Whymarrh


People also ask

Does SQLite insert return ID?

SQLite has a special SQL function – last_insert_rowid() – that returns the ID of the last row inserted into the database so getting the ID of a new row after performing a SQL insert just involves executing the last_insert_rowid() command.

What does insert or ignore do SQLite?

insert or ignore ... will insert the row(s) and ignore rows which violation any constraint (other than foreign key constraints).

Does Rowid change in SQLite?

If the rowid is not aliased by INTEGER PRIMARY KEY then it is not persistent and might change. In particular the VACUUM command will change rowids for tables that do not declare an INTEGER PRIMARY KEY. Therefore, applications should not normally access the rowid directly, but instead use an INTEGER PRIMARY KEY.

What is Rowid in SQLite?

A rowid value is a 64 bit integer. The rowid value can be queried with the rowid keyword. Synonyms for rowid are: oid and _rowid . If a table has a column that is defined to be an integer primary key , this column stores the rowid, that is, the respective column names is an alias for rowid (or vice versa).


1 Answers

The way that worked the best for me was to insert or ignore the values, and the select the rowid in two separate steps. I used a unique constraint on the data column to both speed up selects and avoid duplicates.

sql.execute("INSERT OR IGNORE INTO foo(data) VALUES(?);" ("Some text.", ))
last_row_id = sql.execute("SELECT id FROM foo WHERE data = ?;" ("Some text. ", ))

The select statement isn't as slow as I thought it would be. This, it seems, is due to SQLite automatically creating an index for the unique columns.

like image 94
Whymarrh Avatar answered Sep 23 '22 17:09

Whymarrh