59

I have to find the next available id (if there are 5 data in database, I have to get the next available insert place which is 6) in a MySQL database. How can I do that? I have used MAX(id), but when I delete some rows from the database, it still holds the old max value it didn't update.

OMG Ponies
  • 325,700
  • 82
  • 523
  • 502
Burak Dede
  • 3,725
  • 5
  • 40
  • 53
  • So what you're asking is to find the first available id. If you have 5, but remove the third, then id 3 should be available to insert a new row into? – peirix Sep 10 '09 at 13:49
  • 4
    That's bad advice...most databases simply increment through a sythetic key. They don't try and reuse old values. It just increments. – gshauger Sep 10 '09 at 13:50
  • Burak: do you want to find the "next available id" (which is max(id) + 1), or the "next never-used id"? – nickf Sep 10 '09 at 14:06
  • Possible Duplicate of http://stackoverflow.com/questions/933565/get-auto-increment-value-with-mysql-query – Andrew Jul 16 '12 at 17:28
  • https://www.bram.us/2008/07/30/mysql-get-next-auto_increment-value-fromfor-table/ – Alex Mar 16 '17 at 12:44

15 Answers15

91

Update 2014-12-05

I am not recommending this approach due to reasons laid out in Simon's (accepted) answer as well as Diego's comment. Please use query below at your own risk.


Original answer

The shortest one I found on MySQL developer site:

SELECT Auto_increment
FROM information_schema.tables
WHERE table_name='the_table_you_want'

Mind you if you have few databases with same tables, you should specify database name as well, like so:

SELECT Auto_increment
FROM information_schema.tables
WHERE table_name = 'the_table_you_want'
      AND table_schema = 'the_database_you_want';
informatik01
  • 16,038
  • 10
  • 74
  • 104
Eimantas
  • 48,927
  • 17
  • 132
  • 168
  • 16
    Nice, but don't forget! Other users in the database might insert a record just after you make this query and before you actually insert the record. It works ok for some cases, but keep it in mind! – Diego Jan 04 '13 at 13:41
  • 1
    I tried this, and auto_increment returned null for me. The table I'm selecting from has 5 records, a field called `id` which is the primary key. Could anyone suggest why this is the case? – Lou Jul 21 '14 at 20:51
  • @LeoKing - The column must be an AutoIncrement column to get the value back. – Rafael Herscovici Apr 02 '15 at 11:13
  • The query in this answer can be also used for testing purposes (for example checking if an insert & delete operation really succeeded) – Alberto Oct 05 '15 at 09:37
24

I don't think you can ever be sure on the next id, because someone might insert a new row just after you asked for the next id. You would at least need a transaction, and if I'm not mistaken you can only get the actual id used after inserting it, at least that is the common way of handling it -- see http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html

Simon Groenewolt
  • 10,607
  • 1
  • 36
  • 64
  • I defo agree with this comment. For the data integrity I would always generate and use a fresh number. If you want to use the "unused" id's I recommend to do a php file on a cron job which is executed when there are surely no users in your webapp and you "collaps" your rows to the unused ones. You have to make sure to update any other tables which refer to this one, and update accordingly. – Oliver M Grech Feb 07 '11 at 12:53
  • 11
    @Oliver M Grech: "surely no users in your webapp" - no such thing, the Internet doesn't have working hours. Depending on "oh, it's 2 AM in GMT+1, therefore no users" *will* come back and bite you (been there, done that). – Piskvor left the building Sep 29 '11 at 08:18
22

In addition to Lukasz Lysik's answer - LEFT-JOIN kind of SQL.
As I understand, if have id's: 1,2,4,5 it should return 3.

SELECT u.Id + 1 AS FirstAvailableId
FROM users u
LEFT JOIN users u1 ON u1.Id = u.Id + 1
WHERE u1.Id IS NULL
ORDER BY u.Id
LIMIT 0, 1

Hope it will help some of visitors, although post are rather old.

Jarry
  • 221
  • 2
  • 2
  • Also, instead of the limit and the order by, you can use min(u.id)+1. Not sure which way is faster - probably yours. – Benubird Nov 06 '14 at 10:20
  • To speed this up considerably you should add a group by. " group by u1.id order by u1.id limit 1" – Vincent Oct 10 '19 at 19:46
12

Given what you said in a comment:

my id coloumn is auto increment i have to get the id and convert it to another base.So i need to get the next id before insert cause converted code will be inserted too.

There is a way to do what you're asking, which is to ask the table what the next inserted row's id will be before you actually insert:

SHOW TABLE STATUS WHERE name = "myTable"

there will be a field in that result set called "Auto_increment" which tells you the next auto increment value.

nickf
  • 537,072
  • 198
  • 649
  • 721
11

As I understand, if have id's: 1,2,4,5 it should return 3.

SELECT t1.id + 1
FROM theTable t1
WHERE NOT EXISTS (
    SELECT * 
    FROM theTable t2
    WHERE t2.id = t1.id + 1
)
LIMIT 1
Lukasz Lysik
  • 10,462
  • 3
  • 51
  • 72
  • FYI, there is one gotcha with this code: If there are no rows in the table yet, this will return nothing. – logidelic Dec 01 '17 at 14:44
  • If there are rows in the table, then is this safe? Some of the other answers suggest to use only fresh ID's, but it would be great if we could use this and have data integrity. – Arya Dec 23 '18 at 01:02
4

If you want to select the first gap, use this:

SELECT  @r
FROM    (
        SELECT  @r := MIN(id) - 1
        FROM    t_source2
        ) vars,
        t_source2
WHERE   (@r := @r + 1) <> id
ORDER BY
        id
LIMIT   1;

There is an ANSI syntax version of the same query:

SELECT  id
FROM    mytable mo
WHERE   (
        SELECT  id + 1
        FROM    mytable mi
        WHERE   mi.id < mo.id
        ORDER BY
                mi.id DESC
        LIMIT 1
        ) <> id
ORDER BY
        id,
LIMIT   1

however, it will be slow, due to optimizer bug in MySQL.

Quassnoi
  • 413,100
  • 91
  • 616
  • 614
  • I ran tests on variations of this in MySQL 5.5 for hours. I'm fascinated with the approach, but in no case was this working. In a test case with 1,2,3,5 in a non-indexed column, the first approach returns 7. The second ANSI alternate works even less returning a conflicting 5. Attempts to improve on this design ended in erratic runoff of the @r value or empty results, including attempts to implement a starting reference. I would love to see this working - the idea of creating a variable loop without functions is exciting. – David H. Dec 09 '15 at 14:04
4

you said:

my id coloumn is auto increment i have to get the id and convert it to another base.So i need to get the next id before insert cause converted code will be inserted too.

what you're asking for is very dangerous and will lead to a race condition. if your code is run twice at the same time by different users, they will both get 6 and their updates or inserts will step all over each other.

i suggest that you instead INSERT in to the table, get the auto_increment value using LAST_INSERT_ID(), and then UPDATE the row to set whatever value you have that depends on the auto_increment value.

longneck
  • 11,938
  • 2
  • 36
  • 44
1

If you really want to compute the key of the next insert before inserting the row (which is in my opinion not a very good idea), then I would suggest that you use the maximum currently used id plus one:

SELECT MAX(id) + 1 FROM table

But I would suggest that you let MySQL create the id itself (by using a auto-increment column) and using LAST_INSERT_ID() to get it from the DBMS. To do this, use a transaction in which you execute the insert and then query for the id like:

INSERT INTO table (col1) VALUES ("Text");
SELECT LAST_INSERT_ID();

The returnset now contains only one column which holds the id of the newly generated row.

Xperimental
  • 401
  • 4
  • 13
1

It's too late to answer this question now, but hope this helps someone.

@Eimantas has already given the best answer but the solution won't work if you have two or more tables by the same name under the same server.

I have slightly modified @Eimantas's answer to tackle the above problem.

select Auto_increment as id from information_schema.tables where table_name = 'table_name' and table_schema = 'database_name'
Jay Bhatt
  • 5,601
  • 5
  • 40
  • 62
0

One way to do it is to set the index to be auto incrementing. Then your SQL statement simply specifies NULL and then SQL parser does the rest for you.

INSERT INTO foo VALUES (null);
gshauger
  • 747
  • 4
  • 16
  • my id coloumn is auto increment i have to get the id and convert it to another base.So i need to get the next id before insert cause converted code will be inserted too. – Burak Dede Sep 10 '09 at 13:52
0

If this is used in conjunction for INSERTING a new record you could use something like this.

(You've stated in your comments that the id is auto incrementing and the other table needs the next ID + 1)

INSERT INTO TABLE2 (id, field1, field2, field3, etc) 
VALUES(
   SELECT (MAX(id) + 1), field1, field2, field3, etc FROM TABLE1
   WHERE condition_here_if_needed
)

This is pseudocode but you get the idea

Phill Pafford
  • 83,471
  • 91
  • 263
  • 383
-1

This worked well for me (MySQL 5.5), also solving the problem of a "starting" position.

SELECT
    IF(res.nextID, res.nextID, @r) AS nextID
FROM
    (SELECT @r := 30) AS vars,
    (
    SELECT MIN(t1.id + 1) AS nextID
    FROM test t1
    LEFT JOIN test t2
      ON t1.id + 1 = t2.id
    WHERE t1.id >= @r
      AND t2.id IS NULL
      AND EXISTS (
          SELECT id
          FROM test
          WHERE id = @r
      )
  LIMIT 1
  ) AS res
LIMIT 1

As mentioned before these types of queries are very slow, at least in MySQL.

David H.
  • 355
  • 2
  • 9
-1

The problem with many solutions is they only find the next "GAP", while ignoring if "1" is available, or if there aren't any rows they'll return NULL as the next "GAP".

The following will not only find the next available gap, it'll also take into account if the first available number is 1:

SELECT CASE WHEN MIN(MyID) IS NULL OR MIN(MyID)>1
-- return 1 if it's available or if there are no rows yet
THEN
    1
ELSE -- find next gap
    (SELECT MIN(t.MyID)+1
    FROM MyTable t (updlock)
    WHERE NOT EXISTS (SELECT NULL FROM MyTable n WHERE n.MyID=t.MyID+1))
END AS NextID
FROM MyTable
Doug S
  • 10,146
  • 3
  • 40
  • 45
  • I know I'm very late, but it might be as useful for upcoming visitors as your query was helpful to me :) : you have an extra parenthesis there : `(SELECT MIN(t.MyID))+1` – Pascamel Oct 03 '13 at 06:25
-2
SELECT ID+1 "NEXTID" 
FROM ( 
    SELECT ID from TABLE1 
    WHERE ID>100 order by ID
) "X" 
WHERE not exists (
    SELECT 1 FROM TABLE1 t2
    WHERE t2.ID=X.ID+1
) 
LIMIT 1
Tony Hinkle
  • 4,706
  • 7
  • 23
  • 35
ehuehu
  • 1
-3
<?php
Class Database{
    public $db;
    public $host   = DB_HOST;
    public $user   = DB_USER;
    public $pass   = DB_PASS;
    public $dbname = DB_NAME;

    public $link;
    public $error;

    public function __construct(){
        $this->connectDB();
    }
    private function connectDB(){
    $this->link = new mysqli($this->host, $this->user, $this->pass, $this->dbname);
    if(!$this->link){
        $this->error ="Connection fail".$this->link->connect_error;
        return false;
    }
 }

    // Select or Read data

    public function select($query){
        $result = $this->link->query($query) or die($this->link->error.__LINE__);
        if($result->num_rows > 0){
            return $result;
        } else {
            return false;
        }
    }

}
 $db = new Database();
$query = "SELECT * FROM table_name WHERE id > '$current_postid' ORDER BY ID ASC LIMIT 1";
$postid = $db->select($query);
if ($postid) {
  while ($result = $postid->fetch_assoc()) { 
        echo $result['id'];
    } 

  } ?>