views:

440

answers:

3

How can i know the next free primary key of some model?

A: 

I think you'll have to execute some custom SQL. The SQL you need will be DB specific. As far as I know, there is no reliable way to do this in MySQL. You can get the last insert ID but it is session specific (i.e. you can get the ID of the last record you inserted in your DB session but not the last ID for another session which may have happened after yours). However (and someone correct me if I'm wrong), MySQL generates the next ID with MAX(column_name) + 1 so you could do the same.

PostgreSQL makes it a lot easier with its sequence manipulation functions.

Edit:

Turns out I was thinking of AUTO_INCREMENT columns within a multi-column key which are generated with MAX(column_name)+1. However, the point still stands that there is no way to retrieve the next ID before it is generated by an insert, which was the original question.

Stuart Childs
No, the ID is not MAX(column_name)+1.
Bill Karwin
Yes, you're right. I should've checked since it would be pretty braindead for any multi-user DB to do that.
Stuart Childs
+7  A: 

Even if you can query the next available primary key value, it wouldn't help you. Unless you lock the table, you can't use that value before some other database client might grab it for their insert.

Instead, you should just insert your row, and then you can query the most recent key value generated during your current session. Every database that supports auto-generated primary keys provides a method to retrieve the most recent key inserted during your session.

The "during your session" part is important because it shields your session from any inserts being done concurrently by other clients. They can generate key values and your session will continue to report the same value it inserted most recently.

@Stuart Childs supposes that MySQL generates the next ID with MAX(column_name)+1 but this is incorrect. Say you insert a row and an ID value is generated. But you rollback this insert, or subsequently DELETE that row. The next time you insert, MySQL will generate a brand new ID value. So the ID value is one greater than the last ID value generated by any client, regardless of what rows are currently stored in the table.

Likewise if you insert but don't commit immediately. Before you commit, some other client does an insert. Both your session and the other client's session will have their own unique ID value generated. Auto-generated primary keys operate without regard to transaction isolation, to ensure uniqueness.

Auto-generated primary key values are not re-used or allocated to more than one session, even if you have not yet committed your insert, or if you rollback the insert, or if you delete the row.

Bill Karwin
Ah, the wealth of knowledge.
Paolo Bergantino
Wow, thanks thanks for such detailed explanation.
A: 

I had this same question because I was duplicating an element and I wanted to change its pk to a new one to be able to insert it.

My solution was to do:
import copy
objectCopy=copy.copy(object)
objectCopy.pk=None
objectCopy.save().

I mean, if save() does it for you, why would you want to do it manually...