247

I execute an INSERT INTO statement

cursor.execute("INSERT INTO mytable(height) VALUES(%s)",(height))

and I want to get the primary key.

My table has 2 columns:

id      primary, auto increment
height  this is the other column.

How do I get the "id", after I just inserted this?

1

5 Answers 5

346

Use cursor.lastrowid to get the last row ID inserted on the cursor object, or connection.insert_id() to get the ID from the last insert on that connection.

Sign up to request clarification or add additional context in comments.

5 Comments

What if two processes inserting a row at the same time using the same connection. Which id will insert_id return?
@xiaohan2012 How do 2 processes use the same connection?
Is lastrowid only available after the current transaction being committed?
@hienbt88 He probably meant threads, I've done that and it can cause issues unless you properly utilize threadsafety. I've personally gone for instantiating a new connection for each thread, which is a cute workaround since for some reason committing (autocommitting actually) didn't work for me, I got some serious interweaving due to many concurrent threads all issuing a few queries per second.
Does not works with duplicated records using insert, select and where.
137

Also, cursor.lastrowid (a dbapi/PEP249 extension supported by MySQLdb):

>>> import MySQLdb
>>> connection = MySQLdb.connect(user='root')
>>> cursor = connection.cursor()
>>> cursor.execute('INSERT INTO sometable VALUES (...)')
1L
>>> connection.insert_id()
3L
>>> cursor.lastrowid
3L
>>> cursor.execute('SELECT last_insert_id()')
1L
>>> cursor.fetchone()
(3L,)
>>> cursor.execute('select @@identity')
1L
>>> cursor.fetchone()
(3L,)

cursor.lastrowid is somewhat cheaper than connection.insert_id() and much cheaper than another round trip to MySQL.

8 Comments

Why is cursor.lastrowid cheaper than connection.insert_id()?
Only because cursor.lastrowid is automatically set on the cursor object as part of cursor.execute() and is just an attribute lookup. connection.insert_id() is an additional unnecessary function call - an which has already been called and whose result is available on the lastrowid attribute.
I've just had a problem where cursor.lastrowid returned something different than connection.insert_id(). cursor.lastrowid returned the last insert id, connection.insert_id() returned 0. How can that be?
@moose, maybe concurrent processes are doing parallel database insertion using the same connection.
@FlyingAtom, because this was run on python2 instead of python3.
|
42

Python DBAPI spec also define 'lastrowid' attribute for cursor object, so...

id = cursor.lastrowid

...should work too, and it's per-connection based obviously.

Comments

8
SELECT @@IDENTITY AS 'Identity';

or

SELECT last_insert_id();

3 Comments

this allows for race conditions because you're requesting the last row id from the server. because me, you don't want that mess.
I want to point out this part is equally as important: "Each client will receive the last inserted ID for the last statement that client executed." So you'll get a different value from Workbench than running the exact same select last_insert_id() from the CLI on a Linux machine
0

This might be just a requirement of PyMySql in Python, but I found that I had to name the exact table that I wanted the ID for:

In:

cnx = pymysql.connect(host='host',
                            database='db',
                            user='user',
                            password='pass')
cursor = cnx.cursor()
update_batch = """insert into batch set type = "%s" , records = %i, started = NOW(); """
second_query = (update_batch % ( "Batch 1", 22  ))
cursor.execute(second_query)
cnx.commit()
batch_id = cursor.execute('select last_insert_id() from batch')
cursor.close()

batch_id

Out: 5
... or whatever the correct Batch_ID value actually is

2 Comments

@krzys_h Thanks for looking at this K but your edit fails in my testing and so I have rejected your edit. If you wouldn't mind also backing the edit out?
I think it's true that if the arguments to second_query are user input then there is an SQL injection vulnerability here. Maybe the proposed fix didn't work because update_batch contains "%s". Maybe it would work if it was just %s.

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.