256

How to retrieve inserted id after inserting row in SQLite using Python? I have table like this:

id INT AUTOINCREMENT PRIMARY KEY,
username VARCHAR(50),
password VARCHAR(50)

I insert a new row with example data username="test" and password="test". How do I retrieve the generated id in a transaction safe way? This is for a website solution, where two people may be inserting data at the same time. I know I can get the last read row, but I don't think that is transaction safe. Can somebody give me some advice?

2 Answers 2

370

You could use cursor.lastrowid (see "Optional DB API Extensions"):

connection=sqlite3.connect(':memory:')
cursor=connection.cursor()
cursor.execute('''CREATE TABLE foo (id integer primary key autoincrement ,
                                    username varchar(50),
                                    password varchar(50))''')
cursor.execute('INSERT INTO foo (username,password) VALUES (?,?)',
               ('test','test'))
print(cursor.lastrowid)
# 1

If two people are inserting at the same time, as long as they are using different cursors, cursor.lastrowid will return the id for the last row that cursor inserted:

cursor.execute('INSERT INTO foo (username,password) VALUES (?,?)',
               ('blah','blah'))

cursor2=connection.cursor()
cursor2.execute('INSERT INTO foo (username,password) VALUES (?,?)',
               ('blah','blah'))

print(cursor2.lastrowid)        
# 3
print(cursor.lastrowid)
# 2

cursor.execute('INSERT INTO foo (id,username,password) VALUES (?,?,?)',
               (100,'blah','blah'))
print(cursor.lastrowid)
# 100

Note that lastrowid returns None when you insert more than one row at a time with executemany:

cursor.executemany('INSERT INTO foo (username,password) VALUES (?,?)',
               (('baz','bar'),('bing','bop')))
print(cursor.lastrowid)
# None
Sign up to request clarification or add additional context in comments.

6 Comments

There is also the last_insert_rowid() SQL function, allowing you to insert the last row id as a foreign key in a next insert statement, entirely in SQL.
appears Python's sqlite3 lastrowid uses last_insert_rowid underneath github.com/ghaering/pysqlite/blob/… (which isn't guaranteed threadsafe but seems the only option FWIW). See also stackoverflow.com/q/2127138/32453
Here's the direct link to cursor.lastrowid
Btw, this works for INSERT but does not work for UPDATE. But when updating a row, you probably already have the corresponding row id anyways (just took me a while to figure this out...).
What is meant by "id"? Is it referring to an id column as integer? How does it know, what if I don't have an id column for a certain table?
|
65

All credits to @Martijn Pieters in the comments:

You can use the function last_insert_rowid():

The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. The last_insert_rowid() SQL function is a wrapper around the sqlite3_last_insert_rowid() C/C++ interface function.

SQLite 3.35's RETURNING clause:

CREATE TABLE users (
  id INTEGER PRIMARY KEY,
  first_name TEXT,
  last_name TEXT
);

INSERT INTO users (first_name, last_name)
VALUES ('Jane', 'Doe')
RETURNING id;

returns requested columns of the inserted row in INSERT, UPDATE and DELETE statements. Python usage:

cursor.execute('INSERT INTO users (first_name, last_name) VALUES (?,?)'
               ' RETURNING id',
               ('Jane', 'Doe'))
row = cursor.fetchone()
(inserted_id, ) = row if row else None

5 Comments

The LAST_INSERT_ROWID() function is specific to SQLite. The cursor.lastrowid property is part of the Python DB-API specification so it should be more portable.
Note that the RETURNING clause works with cursor.execute but won't work with cursor.executemany. Python will complain that "executemany() can only execute DML statements."
Depending on your program you should also be careful with race conditions, if multiple threads might be writing to the database in parallel. In that case you can't assume that last_insert_rowid will the row you've just inserted. Thankfully RETURNING can now be used to solve this, although it's not yet available everywhere.
SQLite only allows a single writer at once, so that shouldn't be possible @laurent. No?
That would be possible if something writes to the database between your write and the moment you call last_insert_rowid.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.