19
SELECT LAST_INSERT_ID() as id FROM table1

Why does this query sometimes return the last inserted id of another table other than table1? I call it in Node.js (db-mysql plugin) and I can only do queries.

Jeremy W
  • 1,889
  • 6
  • 29
  • 37
ElSajko
  • 1,612
  • 3
  • 17
  • 37

8 Answers8

38

LAST_INSERT_ID() can only tell you the ID of the most recently auto-generated ID for that entire database connection, not for each individual table, which is also why the query should only read SELECT LAST_INSERT_ID() - without specifying a table.
As soon as you fire off another INSERT query on that connection, it gets overwritten. If you want the generated ID when you insert to some table, you must run SELECT LAST_INSERT_ID() immediately after doing that (or use some API function which does this for you).

If you want the newest ID currently in an arbitrary table, you have to do a SELECT MAX(id) on that table, where id is the name of your ID column. However, this is not necessarily the most recently generated ID, in case that row has been deleted, nor is it necessarily one generated from your connection, in case another connection manages to perform an INSERT between your own INSERT and your selection of the ID.

(For the record, your query actually returns N rows containing the most recently generated ID on that database connection, where N is the number of rows in table1.)

AAEM
  • 1,837
  • 2
  • 18
  • 26
Michael Madsen
  • 54,231
  • 8
  • 72
  • 83
  • I heard that MAX(id) dont work well enough when there are too many inserting rows. And then we have duplicats. – ElSajko Aug 25 '12 at 21:12
  • 1
    @KamilKrzyszczuk: Correct, which is why you don't do it for IDs you just generated. When I say "in an arbitrary table", that means "some table other than the one you just inserted into on this connection". If you need to generate IDs in mutiple tables and use all of them in a subsequent, you have to select them (using `SELECT LAST_INSERT_ID()`) after each INSERT. – Michael Madsen Aug 25 '12 at 21:33
  • I do, but in two queries. Can I do INSERT and SELECT last_insert_id() in one query? – ElSajko Aug 26 '12 at 13:59
  • @Kamil: You can send multiple queries at once (if your database API allows it), but that isn't necessary, so long as it's the same *connection*, and you aren't doing something funky like simultaneously using the same connection for two different requests (and you should know if you are). – Michael Madsen Aug 26 '12 at 14:38
  • 1
    so what now, i have to do something like this? "INSERT INTO table1(test) VALUES('test'); SELECT LAST_INSERT_ID()" and then last insert id will be from table1? – ElSajko Aug 26 '12 at 16:42
  • @Kamil: Yes, but you can also use two separate query calls, and `SELECT LAST_INSERT_ID()` will still be from table1. – Michael Madsen Aug 26 '12 at 16:51
  • I do two separate query calls and still sometimes get last insert id from another table. But I do this in node.js with db-mysql plugin. I think this is about async query calls: database.query().execute(query, function(error, rows, cols) {}); So can two queries in one call fix it? – ElSajko Aug 26 '12 at 17:28
  • @KamilKrzyszczuk: I'm not familiar with your DB plugin, so I can't say, but if you are otherwise doing everything correctly, that does sound like the insert query isn't completed before the select, which could happen with an asynchronous call. I would just make it synchronous instead; you need to wait for the query to finish anyway if you want to do something with the generated ID. – Michael Madsen Aug 26 '12 at 17:39
  • I can do that. Btw. It may be because as you said insert query isn't completed before the select, OR because between insert and select query is insert query of this another table, coz this query is calling in another thread I think (when client post some msg) So i think the best way will be put insert and select in one query like above i wrote. But is it correct for mysql? – ElSajko Aug 26 '12 at 21:05
  • @KamilKrzyszczuk: I don't know enough about your system to know how you're implementing this, or how your DB plugin works (or Node.js, for that matter), so I can't answer that - check the documentation. The key is really to make sure that all queries are executed in a consistent order; if multiple threads are using a connection, you can get incorrect results if more than one is inserting. – Michael Madsen Aug 26 '12 at 21:18
  • @MichaelMadsen: How does this Last_Insert_id() differ with MSSQL Server Scope_Identity()? Because MSSQL Server Scope_Identity() can assign the last inserted id for each table. Is it possible to do this with MySQL? Is their anyway to do it? I just switched from MSSQL Server to MySQL so i want to apply what i had learned from it, but it seems not working. – Jansen Malaggay Oct 03 '18 at 15:36
  • @MichaelMadsen what if `id` is autoincremental and records have been deleted? Selecting `MAX(id)` will return `Null`. What can be done in that case? – Stefano Messina Mar 27 '19 at 14:36
  • @StefanoMessina That will only be the case if the table is *empty*. If there are any rows, it will return the one with the largest ID, regardless of gaps. What you want to do in that case depends entirely on your specific scenario (as already mentioned, it is unrelated to activity on your current connection, and as such, rarely what you are actually after anyway), but https://stackoverflow.com/questions/15821532/get-current-auto-increment-value-for-any-table shows how to obtain the next value that *will* be used. – Michael Madsen Mar 27 '19 at 18:09
  • @MichaelMadsen yes! that's exactly what I did! – Stefano Messina Mar 28 '19 at 13:43
3

SELECT id FROM tableName ORDER BY id DESC LIMIT 1

Hitesh
  • 109
  • 7
1

Try this. This is working

select (auto_increment-1) as lastId
from information_schema.tables
where table_name = 'tableName'
and table_schema = 'dbName'
  • This is too dangerous because it's global table. You may get last id caused by other insert statement in some other process. – Scott Chu May 12 '17 at 04:05
0

I usually select the auto-incremented ID field, order by the field descending and limit results to 1. For example, in a wordpress database I can get the last ID of the wp_options table by doing:

SELECT option_id FROM wp_options ORDER BY option_id DESC LIMIT 1;

Hope that helps.

Edit - It may make sense to lock the table to avoid updates to the table which may result in an incorrect ID returned.

LOCK TABLES wp_options READ;
SELECT option_id FROM wp_options ORDER BY option_id DESC LIMIT 1;
recurse
  • 624
  • 6
  • 15
  • If another insert occurs outside a transaction this will be incorrect and give the wrong ID. Single Transaction, multiple statements, with last_insert_id() will ensure that the result is the true inserted id. – ShellNinja Nov 02 '16 at 16:10
  • @ShellNinja - If another insert occurs, in a different table, outside the transaction, last_insert_id() will give you the wrong result. Selecting the last ID of the current table, with a possible LOCK at the time of query is probably most reliable. LOCK TABLES wp_options READ; SELECT option_id FROM wp_options ORDER BY option_id DESC LIMIT 1; – recurse Nov 02 '16 at 17:12
0

Most easy way: select max(id) from table_name;

Bart Mensfort
  • 995
  • 11
  • 21
0

I only use auto_increment in MySQL or identity(1,1) in SQL Server if I know I'll never care about the generated id.

select last_insert_id() is the easy way out, but dangerous.

A way to handle correlative ids is to store them in a util table, something like:

create table correlatives(
    last_correlative_used int not null, 
    table_identifier varchar(5) not null unique
);

You can also create a stored procedure to generate and return the next id of X table

drop procedure if exists next_correlative;
DELIMITER //
create procedure next_correlative(
    in in_table_identifier varchar(5)
)
BEGIN
    declare next_correlative int default 1;

    select last_correlative_used+1 into next_correlative from correlatives where table_identifier = in_table_identifier;

    update correlatives set last_correlative_used = next_correlative where table_identifier = in_table_identifier;

    select next_correlative from dual;
END //
DELIMITER ;

To use it

call next_correlative('SALES');

This allows you to reserve ids before inserting a record. Sometimes you want to display the next id in a form before completing the insertion and helps to isolate it from other calls.

Here's a test script to mess around with:

create database testids;

use testids;

create table correlatives(
    last_correlative_used int not null, 
    table_identifier varchar(5) not null unique
);

insert into correlatives values(1, 'SALES');

drop procedure if exists next_correlative;
DELIMITER //
create procedure next_correlative(
    in in_table_identifier varchar(5)
)
BEGIN
    declare next_correlative int default 1;
    select last_correlative_used+1 into next_correlative  from correlatives where table_identifier = in_table_identifier;
    update correlatives set last_correlative_used = next_correlative where table_identifier = in_table_identifier;
    select next_correlative from dual;
END //
DELIMITER ;

call next_correlative('SALES');
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Wesos de Queso
  • 1,526
  • 1
  • 21
  • 23
0

If you want to use these workarounds:

  • SELECT id FROM tableName ORDER BY id DESC LIMIT 1
  • SELECT MAX(id) FROM tableName

It's recommended to use a where clause after inserting rows. Without this you are going to have inconsistency issues.

  • That assumes that `id` is numeric and increases over time. It will break if IDs are e.g., UUIDs or are picked randomly otherwise. – Robert Dec 07 '21 at 20:06
-1

in my table inv_id is auto increment

for my purpose this is worked

select `inv_id` from `tbl_invoice`ORDER BY `inv_id` DESC LIMIT 1;
jizhihaoSAMA
  • 12,336
  • 9
  • 27
  • 49