代码之家  ›  专栏  ›  技术社区  ›  Burak Dede

在MySQL中查找下一个可用的ID

  •  47
  • Burak Dede  · 技术社区  · 15 年前

    我必须在MySQL数据库中找到下一个可用的ID(如果数据库中有5个数据,我必须得到下一个可用的插入位置,即6)。我该怎么做? 我已经用过 MAX(id) ,但是当我从数据库中删除一些行时,它仍然保留着它没有更新的旧max值。

    15 回复  |  直到 8 年前
        1
  •  19
  •   Simon Groenewolt    15 年前

    我想你永远不能确定 下一个 ID,因为有人可能会在您请求下一个ID后插入新行。您至少需要一个事务,如果我没有弄错,您只能使用实际的ID 之后 插入它,至少这是处理它的常用方法——请参见 http://dev.mysql.com/doc/refman/5.0/en/getting-unique-id.html

        2
  •  85
  •   cmc Brian Carper    9 年前

    2014-12-05更新: 由于西蒙(接受)的回答以及迭戈的评论中列出的原因,我不建议采用这种方法。请自行承担风险使用下面的查询。

    我在MySQL开发人员网站上找到的最短的一个:

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

    请注意,如果有几个数据库具有相同的表,则还应指定数据库名称,如下所示:

    SELECT Auto_increment FROM information_schema.tables WHERE table_name='the_table_you_want' AND table_schema='the_database_you_want';
    
        3
  •  17
  •   Jarry    14 年前

    除了LukaszLysik的答案——左连接类型的SQL。
    据我所知,如果ID为:1、2、4、5,则返回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
    

    希望它能帮助一些参观者,尽管这篇文章相当陈旧。

        4
  •  10
  •   nickf    15 年前

    鉴于你在评论中所说的:

    我的ID列是自动递增的,我必须获取ID并将其转换为另一个基,所以在插入之前我需要获取下一个ID,因为转换后的代码也将被插入。

    有一种方法可以做到你所要求的,那就是问桌子 下一插入行的ID 在实际插入之前:

    SHOW TABLE STATUS WHERE name = "myTable"
    

    结果集中会有一个名为“自动增量”的字段,它告诉您下一个自动增量值。

        5
  •  10
  •   Lukasz Lysik    15 年前

    据我所知,如果ID为:1、2、4、5,则返回3。

    SELECT t1.id + 1
    FROM theTable t1
    WHERE NOT EXISTS (
        SELECT * 
        FROM theTable t2
        WHERE t2.id = t1.id + 1
    )
    LIMIT 1
    
        6
  •  4
  •   longneck    15 年前

    你说:

    我的ID列是自动递增的 获取ID并将其转换为 另一个基地,所以我要接下一个 插入原因转换代码前的ID 也将插入。

    你所要求的是非常危险的,会导致比赛条件。如果您的代码由不同的用户同时运行两次,那么他们都将得到6个,并且他们的更新或插入将逐步进行。

    我建议你改为 INSERT 在表中,使用 LAST_INSERT_ID() 然后 UPDATE 要设置的值取决于自动增量值的行。

        7
  •  3
  •   Quassnoi    15 年前

    如果要选择第一个间隙,请使用:

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

    有一个 ANSI 同一查询的语法版本:

    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
    

    但是,由于优化器在 MySQL .

        8
  •  1
  •   Xperimental    15 年前

    如果您真的想在插入行之前计算下一个插入的键(我认为这不是一个很好的主意),那么我建议您使用当前使用的最大ID加上一个:

    SELECT MAX(id) + 1 FROM table
    

    但是我建议您让MySQL自己创建ID(通过使用自动增量列)并使用 LAST_INSERT_ID() 从数据库管理系统中获取。为此,请使用执行插入操作的事务,然后查询ID,如下所示:

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

    返回集现在只包含一列,其中包含新生成行的ID。

        9
  •  1
  •   Jay Bhatt    9 年前

    现在回答这个问题已经太迟了,但希望这能帮助别人。

    @Eimantas已经给出了最佳答案,但是如果在同一服务器下有两个或多个同名表,那么解决方案将无法工作。

    我稍微修改了@eimantas的答案以解决上述问题。

    select Auto_increment as id from information_schema.tables where table_name = 'table_name' and table_schema = 'database_name'
    
        10
  •  0
  •   gshauger    15 年前

    一种方法是将索引设置为自动递增。然后您的SQL语句简单地指定了空值,然后SQL解析器为您完成其余的工作。

    INSERT INTO foo VALUES (null);
    
        11
  •  0
  •   Phill Pafford    15 年前

    如果将它与插入新记录结合使用,则可以使用类似的方法。

    (您已经在注释中声明了ID是自动递增的,而另一个表需要下一个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
    )
    

    这是伪代码,但你知道

        12
  •  -1
  •   Doug S    11 年前

    许多解决方案的问题是,它们只找到下一个“间隙”,而忽略“1”是否可用,或者如果没有任何行,它们将返回空值作为下一个“间隙”。

    以下内容不仅可以找到下一个可用的间隙,如果第一个可用的数字是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
    
        13
  •  -1
  •   David H.    9 年前

    这对我(MySQL5.5)很有效,也解决了“开始”位置的问题。

    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
    

    如前所述,这些类型的查询非常慢,至少在MySQL中是如此。

        14
  •  -2
  •   Tony Hinkle ravikanth    9 年前
    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
    
        15
  •  -2
  •   Mahmudul Hasan    8 年前
    <?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'];
        } 
    
      } ?>