Sat October 11th 2008 8:09 am Blog | Gallery | Geek | Travels | Home | Contact | Archives | Links
Tux
Blog Gallery Geek Travels Home Contact Archives Links
MP3 Playlist Generator
MySQL: Get Next Auto_increment
PHP Fortune
Recurses! Foiled again....
Kernel Watch
Get yer PHP Referrers here

Geek : MySQL: Get Next Auto_increment

MySQL: Get Next Auto_increment
Thursday April 24th, 2003

** It is not recommended to use this method for generating foreign keys for lookups. In a multiuser environment with simultaneous requests the results will be utterly useless and unreliable. OK? **

So I was working on the preview feature of the home grown content management system for this site, and I came across an interesting problem for which my friend Google had no answers.

The way the preview feature works is that when editing an entry, you hit the PREVIEW button, and the script posts the edited data unto itself and then writes it to a temp file named {section}_{entry ID}.php. When the posted page loads, it opens a new window with the template for the given section, and the POST data is processed in the content well, just as any other entry would be.

The problem is that if you want to create a NEW entry, you don't have an entry ID to assign to the tempfile name, and therefore the preview feature does not work. So I needed a way of finding out what MySQL would assign as the next auto_increment entry ID if I were to actually insert a record. My first thought was to simply get the highest existing ID from the table and add 1, but that is not a perfect solution. For one thing, there is the possibility that another author might insert a new record during the time that I'm previewing, which will cause some confusion -- we might end up with two instances of the temp file overwriting one another. No good. Also, the highest existing ID + 1 is NOT necessarily the next auto increment ID, because when entries are deleted, the entry ID is not reused. So it's conceivable that if your highest ID is 500, the next ID might be 501, or it might be 5001 for all we know.

I was on a mission.

So, I looked all over the web for a solution, and found several similar scenarios described, but no answers. In fact, I came across several forums and help sites where it was actually stated as fact that you CANNOT get the next auto_increment. I knew this to be false, because this information is displayed in the table structure view of phpMyAdmin. So I scoured the source code of phpMyAdmin, and after many desperate combinations of GREPs, FINDs, and XARGSs, I finally came up with this: (assumes we're already connected to the dB)

And the rundown:

"SHOW TABLE STATUS" produces a two-dimensional array with one row for each table, and a slew of columns: Name, Type, Row_format, Rows, Avg_row_length, Data_length, Max_data_length, Index_length, Data_free, Auto_increment, etc.

So what I'm doing here is using mysql_fetch_assoc() to get the "Auto_increment" value.

And there you have it. Our next likely entry ID, without inserting anything.

edited by JD on 2/14/06

Oh the drama

Posted by Jamie
Comments: 65
Previous EntryNext Entry

Comments: (65)

Nice, but this is even better:

SHOW TABLE STATUS LIKE "table_name";

Posted by Nate on 11/30/03 at 7:28 AM EST

Hey thanks!

SHOW TABLE STATUS LIKE "table_name";

works like a charm and was exactly what I needed. Thanks Jamie (and Nate).

Posted by Michael on 12/16/03 at 8:28 PM EST

thanks Nate. That's MUCH better!
You're welcome Michael.

Posted by Jamie on 1/16/04 at 4:48 PM EST

Nice work! Your page came up first in my google search for this exact problem.

Posted by chris on 4/16/04 at 1:42 AM EST

How can I create a table out of the SHOW STATUS TABLE information ?
e.g.
Create table stati as SHOW STATUS TABLE;
does not work.

Posted by Richard on 4/30/04 at 8:34 AM EST

Not at all sure what you're trying to do but I don't think it works.
RTFM: MySQL Manual

Posted by Jamie on 5/6/04 at 5:26 PM EST

If I use "SHOW TABLE STATUS LIKE "table_name";" in a phpMyAdmin, I can see auto_increment number, but when I use it with the rest of above code on a php page, I get nothing for "$qShowStatusResult", $entry_id and "$qShowStatus". Do you know how to get auto_increment value on php webpage? Thanks

Posted by Mike Young on 5/23/04 at 10:22 PM EST

Here's an example using "SHOW TABLE STATUS LIKE 'table_name'" (again, we've already established a connection to the database. Consult the PHP manual if you don't know how to do this.):

Posted by Jamie on 5/24/04 at 12:04 AM EST

Thanks guys! Works good except there's a slight omission in the final example.
The line starting with

$qShowStatus = "SHOW TABLE STATUS LIKE 'tablename'";

should read

$qShowStatus = "SHOW TABLE STATUS LIKE '$tablename'";

cheers

Posted by Kris M on 8/20/04 at 2:56 PM EST

Dear Friend.
Thank you very much for the solution for the problem of getting the next auto number.
I really appriciate your kindness for sharing it.

sincerely:
Mikiko

Posted by Mikiko on 11/13/04 at 10:41 PM EST

Many thanks

I had the same problem.

From the code above I put together a function
to get the next number.

Maybe it will be usefull to someone.

-I have a function connect_db()
(I am shure you can guess what it does.)


function next_auto_incriment($tablename)
{
connect_db();
//$tablename = "downloads";
$next_increment = 0;
$qShowStatus = "SHOW TABLE STATUS LIKE '$tablename'";
$qShowStatusResult = mysql_query($qShowStatus) or die ( "Query failed: " . mysql_error() . "
" . qShowStatus );


while ($row = mysql_fetch_assoc($qShowStatusResult)) {
$next_increment = $row['Auto_increment'];
}
mysql_free_result($qShowStatusResult);

return $next_increment;
}

Posted by Phil on 11/24/04 at 8:46 PM EST

Thats what i was searching for :D tried so many possibilities. now it works. Thanks

Posted by Jan on 1/13/05 at 6:11 AM EST

Why do you have this in a while loop? It's returning only one row...

$row = mysql_fetch_assoc($qShowStatusResult);
$next_increment = $row['Auto_increment'];

But good, learning about SHOW TABLE STATUS is handy!

Posted by grrr on 2/28/05 at 3:00 AM EST

try this:

select max(id) from my_table;

Posted by peter on 3/1/05 at 7:08 AM EST

Thanks peter, but you didn't read the entry.

Posted by Jamie on 3/1/05 at 9:28 AM EST

Wow. This was more helpful than the MySQL manual. Thank you so much. <3

Posted by twig on 3/25/05 at 10:34 PM EST

wow very very nice.

i was with the exactly problem doing a Portal for a brazilian university using JSP and i that came up in my first google search... thanks a lot

Posted by Marvin on 5/4/05 at 2:08 PM EST

Fantastic - thanks for this - I spent 2 days trying to sort this problem. Then googled to here and it was sorted in 5 minutes.

Posted by John Harrison on 5/18/05 at 11:51 AM EST

"There is no "nextval", please use your own function" - mysql team. Damn. That's the one of reasons why avoid mysql when it is possible. Thank You very much for this tutorial.

Posted by Tomas on 5/25/05 at 3:12 AM EST

Great Job! Thanks everybody for your commments, They were truly useful! :)

Posted by Nkm on 5/27/05 at 2:23 AM EST

thanks, this helped.. haha. go corporate work!

Posted by joe on 8/17/05 at 3:17 PM EST

oh yeah, my third cent, would be to make the actual title of these dynamic pages the title of the article (MySQL: Get Next Auto_increment). i found it on google easy, but it'll always help. worrrrrrrrrd

Posted by joe on 8/17/05 at 3:19 PM EST

Good tip, joe. I've taken your advice.

Posted by JD on 8/17/05 at 3:31 PM EST

Thanks for this! Found this from google, worked like a charm.

Posted by Jim Connolly on 8/24/05 at 8:58 AM EST

Found from google, godly information.

Posted by Nicholas Ang on 9/4/05 at 8:20 AM EST

Thanks! I had the same problem ... :)

Posted by Gagi on 9/9/05 at 11:41 AM EST

haha much the same everyone else here! that helped so much for message board cheers! :D

Posted by Dave on 10/6/05 at 11:02 AM EST

This is a nice solution, and I thank you for posting it.
However, you could still have the problem of two records with the same ID and could still end in overwriting records.

Posted by Brad on 10/7/05 at 12:13 PM EST

Keep in mind I'm only using the retrieved ID for preview purposes -- I don't actually insert the ID value into the table. So the possibility exists that I might be previewing the wrong entry, but overwriting is not an issue.

Posted by Jamie on 10/7/05 at 12:29 PM EST

I just want to thank you for this solution.
I am very thankful for that, and google of course... my way of finding this page.

And that "SHOW TABLE STATUS LIKE 'tablename'" is very good.
Keep up the good work.

Posted by James on 2/14/06 at 4:05 PM EST

OK. Just to clean it up a little, I'm updating the original code snippet to include everyone's helpful comments. Thanks! Here it is, again with a pre-established DB connection:

Posted by Jamie on 2/15/06 at 1:50 AM EST

Awesome. *Execatly* what I was looking for. Kudos. I think you may have to put a "$" in front of ".qShowStatus" on line 5 your example above.

edited on 2/22 by Jamie: Done. Thanks, OG.

Posted by Ottergoose on 2/22/06 at 6:36 PM EST

You're my hero :) First Google result for "php get next auto_increment" too...thanks!

Posted by Joshua on 3/16/06 at 11:45 PM EST

First site on google when searching for "mysql 'get the auto_increment value'" Thanks

Posted by Bill on 3/22/06 at 5:50 PM EST

Thanx!!!!

Posted by Malboy on 3/27/06 at 10:47 PM EST

Thanx, thanx, thanx!! It's second result for "next autoincrement mysql" query in google. It's realy works and it's realy healpful. I also have one tip: If some times U need to save some file using name autoID.ext where autoID is next autoincrement, use a file locking function (open and lock file):

[code]
open&lock_file();
get_nextautoincrement();
save_uploaded_autoID_file();
makeSQLquery();
unlock_file();
[/code]

It's helpful when two instance of your script runs in same time - you make sure that a uploaded file an database entry have same ID.

maciejkiner.oneclick.pl

Posted by maciejkiner on 4/2/06 at 10:22 AM EST

Nice work. Thanks for sharing.

Posted by Stephen on 5/22/06 at 7:35 PM EST

This is precisely the problem that I've been facing. Brilliant.

Posted by Dean Felch on 6/28/06 at 2:22 PM EST

Excellent information, that is what I needed. Found you from Google!

Posted by Shain on 7/20/06 at 12:37 AM EST

How do I do the same using Java and MySQL?
When I ran the query, SHOW TABLE STATUS LIKE '$tablename', it was erroring out. Is there any diff. with the command in Java?

Posted by skg on 8/1/06 at 12:22 AM EST

Is this transaction/thread safe? (Obviously, in a very populate application)
Can you rely on the next auto increment to match the one used in your subsequent INSERT statement.

This is why Oracle uses Sequences rather than embedding them into the table.

I am currently doing this.
INSERT INTO mytable (session) VALUES ('$session');
SELECT max(id) from mytable where session=$session;

Any thoughts, am I being too cautious?

Posted by TimTime on 8/5/06 at 4:07 PM EST

Just answered my own point.

Use mysql_insert_id();

Don't know why you would want to predict the number in advance, but if you want to ensure your application is thread safe I'd advise the above.

Posted by TimTime on 8/5/06 at 4:13 PM EST

great solution... but some of your veiwers/readers are a little slow. :)

Posted by Sammy on 8/22/06 at 9:55 AM EST

i'm rather experienced with mysql doing lots of databases with lots of users online at same time... the only situation i need to predict next auto_increment value is if i have to insert/update the id of a fresh record from A-table to one or more fields from B-table (eg. A-table - a new house form a real estate agency database; B-table - pictures table which has more records for same house) the best sollution is to begin a transaction using

$conn=mysql_query("START TRANSACTION"); //lock transaction
$conn=mysql_query("SHOW TABLE STATUS LIKE '$tablename'");//run next-id-returning-query
$nid=mysql_fetch_assoc($conn);//fetch
$conn="INSERT INTO `house` (data1, data2) VALUES ('data1', 'data2')";//insert new house
$conn="INSERT INTO `pictures` (id, pic, thumb) VALUES ('{$nid['Auto_Increment']}', 'pic', 'thumb')"; //in a loop for each picture of that house
$conn=mysql_query("COMMIT");//write data & unlock transaction

this means that since you started the transmision no other user will increment the next_auto_increment value by recording a new house... just don't forget to commit changes...

Posted by SRDJaN on 8/26/06 at 7:38 PM EST

i forgot to tell you that u can use

$conn=mysql_query("select max(last_insert_id(auto_increment_field_name)) from `table`");

and then fetch the output for manualy setting the id value to last_insert_id+1 but i'm not sure if in default settings of the server it allows you to actualy do that... this is useful if you have a lot of data in your table with lot of missing records (eg field id's: 1, 45, 200, 1400 are in sequence because others have been deleted) and you are forced to use a for-loop (because you have to extract records by id ((stored and deleted at same time)) from other places) and it's faster doing a a big selection using the between criteria and excluding localy unwanted then using where id=xx for each id because this way ure a using clients resources for each client not servers for thousands of clients

Posted by SRDJaN on 8/26/06 at 7:54 PM EST

post before is usefull in case inner join is not a solution in your case :)

Posted by SRDJaN on 8/26/06 at 7:58 PM EST

what about 2 simultaneous insertions for example? will your system give two same ID ? or mixed data?
You should use Transaction for safety, if more than one person can act simultaneously. You can use InnoDB table with transaction for example

Posted by zoomy on 8/31/06 at 9:31 AM EST

great job Jamie ! thanks

Posted by radu on 11/21/06 at 3:48 PM EST

great bit of code was exactly what i was looking for. i wrote a clunky thing using MAX() which worked as long as no-one deleted the last record, doh!

cheers, you're a star!

Posted by wiggy on 12/17/06 at 8:46 AM EST

Hi, this is THE BEST OF THE BEST post and you guys are my heroes.
Tnx alot!!!!

Posted by Benny on 1/9/07 at 4:04 PM EST

Thanks Jamie and all. This was something I needed and it seems to work fine. Worth noting (not sure if this is a new requirement as of php5--which is what I'm using) but the script's opening tag needs to be specified as:

Posted by glutimouse maximouse on 3/21/07 at 11:16 PM EST

LIKE is slow .. use:
$sql = "SHOW TABLE STATUS WHERE Name='TABLE_NAME'";

Posted by evin on 4/9/07 at 2:46 AM EST

Clever solution to what should be a non-problem. Autoinc primary keys should be for internal db use only and have no meaning outside the database: that is a basic principle of db design theory.

Now neither transaction nor table locks are going to stop SHOW TABLE STATUS, indeed that is the prescribed method for examining table lock status. So any number of concurrent users are going to see the same autoinc value. Of course only one will be able to use it correctly, all others will then end up with the wrong value.

The only method to use is that described in the MySQL documentation: do your insert then query for last_insert_id. This is not the documented method for no reason, it is because it is the one that will work.

What continually amazes me is why so many of you continue to try to find a way around fundamental relational database behaviour. This is not peculiar to MySQL, it is normal behaviour in all the RDBMS that I know of.

When you do want to predict and control the next id, eg for an unbroken sequence of invoice numbers, then you have to create your own process which you can use either transactions and/or table locks with. Otherwise, it is what it is so just live with it.

Posted by David Soussan on 4/10/07 at 3:17 PM EST

Arrogant, self-righteous, and condescending. And you didn't read the thread either. Glad to have met you, David!

Posted by Jamie on 4/11/07 at 9:57 AM EST

What's the matter, Jamie? Can't take pertinent criticism?

And yes, I read the thread, as I did the one on PHPBuilder where I found the link to your blog.

Calling me names is not going to change the truth of my comments. I'm not the only one to point out the flaws, TimTime has already done so. I just explained the problem in detail.

I don't want to getting into some flaming row - it's your blog after all. I just worry about the poor folk who naively adopt your solution without realising the major bug they are setting up by doing so.

Posted by David Soussan on 4/13/07 at 6:55 PM EST

Your criticism is unfair. There is no bug here. I don't want those "poor folks" to use this information in any way that I am not. And I am using it, essentially, for internal db use. It's a PREVIEW feature. For a website that only I have access to. There will never be anyone else getting the same number, so it's a non-issue. That's why I suggested perhaps you didn't read, or didn't soak in, the whole thread. But I appreciate your contribution -- I'd just rather it be delivered in a more diplomatic way.

Posted by Jamie on 4/13/07 at 7:16 PM EST

While this works, it does not work in all cases. Also, to answer the question of "why would you ever do need this?" I have that as well.

I have a table that stores the location of pictures along with its width, height, and a timestamp.

The picture name is the same as the Auto_incremented ID (ProjectImageID in this case). This is done for who knows what reason, but I did not make it this way, but it what I inherited. Anyways, the last column in the table is Timestamp where I put store NOW() for record keeping.

Whenever I run this solution, I get the timestamp value returned and have yet to been able to get the ProjectImageID increment value to return.

Posted by Dustin on 5/24/07 at 2:58 AM EST

You rock! thx a ton!

Posted by Ken on 7/8/07 at 2:44 PM EST

Just want to say thanks for your original postings. I'd been looking for this code for a while but everyone kept telling me it could not be done, although like you I reasoned that if phpAdmin could display the number then it must be available somewhere.

Posted by Steve on 7/16/07 at 5:57 PM EST

Thank you very much for that tip! I didn't know about table status. This page came up in Google when searching on how to change AUTO_INCREMENT.

Posted by matt on 7/27/07 at 12:34 AM EST

Thanks very much for that tip !

Posted by Capripot on 8/16/07 at 4:50 PM EST

Hey man!! thank u! it worked perfectly!! just what I needed!

Posted by Josh on 11/5/07 at 8:10 AM EST

Not a solution for this problem, but a related useful function is:
mysql_insert_id()
which returns the autoincrement-number from the last executed insert-command.

Posted by Rattle-Head on 1/27/08 at 4:58 AM EST

Still useful 5 years on!

Posted by Kev on 4/2/08 at 7:03 AM EST

Excellent and useful piece of coding.

I have used it for my site drurl.net, which allows people to shorten their urls.

I needed to know if someone is linking to a number that has been permanently removed or not yet been created, as I delete a lot of urls there may be a big gap at the end of the database auto_increment and +1 to the last ID number does not work.

Your code allows this exactly.

Cheers.

David

PS. I hate captcha

Posted by David on 5/2/08 at 1:33 AM EST


Your 2¢ (comments subject to approval)
The Captcha image Phonetic spelling (mp3)
© 2003 Jamie Doris Blog | Gallery | Geek | Travels | Home | Contact | Archives | Links