如何在mysql中获取下一个自动增量ID


113

如何在MySQL中获取下一个ID以将其插入表中

INSERT INTO payments (date, item, method, payment_code)
VALUES (NOW(), '1 Month', 'paypal', CONCAT("sahf4d2fdd45", id))

1
使用auto_increment专栏
knittl

您要使用下一个 ID还是当前要插入的行的ID?也就是说,付款代码末尾的ID是否应为存储付款代码的行的ID?
麦克,

我当前要插入的行的ID
faressoft 2011年

6
在这种情况下,请在检索值时串联它们,而不是在插入它们时串联它们。这种方法要容易得多,并且您排除了输入错误的ID或必须运行更新的可能性-考虑一下如果在更新有机会运行之前,另一个客户端请求了刚插入的行,那么会发生什么情况:最终将带有无效的付款代码。在低流量的系统上,可能不会发生这种情况,但是我看不出冒险的意义。
麦克,

...或正如@binaryLV所指出的那样,资源锁定也可以解决问题。参见:dev.mysql.com/doc/refman/5.5/en/lock-tables.html
麦克

Answers:


12

使用LAST_INSERT_ID()从您的SQL查询。

要么

您也可以mysql_insert_id()使用PHP来获取它。


13
@Sarfraz:问题是关于下一个 ID,而不是您所说的LASTLAST_INSERT_ID()
菲利佩·佩雷拉

1
如果表中的行被删除,则最大值将是错误的
peterchaula

只是来自'17的注释-不建议使用mysql *函数-可以通过以下方式完成mysqli_insert_id
treyBake

谁将此标记为答案?问题是关于下一个插入ID不是最后一个。
阿米特·沙

251

您可以使用

SELECT AUTO_INCREMENT
FROM information_schema.tables
WHERE table_name = 'table_name'
AND table_schema = DATABASE( ) ;

或者,如果您不想使用information_schema,则可以使用此方法

SHOW TABLE STATUS LIKE 'table_name'

感谢前两个选项。.但是第三个只是从PHP调用的第二个。.不知道是什么使大型数据库上的速度更快...
Gerard ONeill 2016年

1
@GerardONeill删除了它
ravi404 '16

3
因为使用了缓存来从information_schema.tables中检索数据,所以该解决方案不再对mysql 8起作用
Bruno

1
@Bruno您可以发布参考吗?
mvorisek

1
此官方文档状态TABLES.AUTO_INCREMENT已缓存dev.mysql.com/doc/refman/8.0/en/… 。也MySQL的博客有几个后这件事,但他们提到的系统varaible似乎已经过时:mysqlserverteam.com/... mysqlserverteam.com/...
布鲁诺

50

您可以通过执行以下操作获得下一个自动增量值:

SHOW TABLE STATUS FROM tablename LIKE Auto_increment
/*or*/
SELECT `auto_increment` FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = 'tablename'

请注意,您应使用此修改表,使用AUTO_INCREMENT列要做到这一点,而不是自动。
问题是last_insert_id()追溯的,因此可以在当前连接中得到保证。
该婴儿是准婴儿,因此并非每次连接都唯一,因此不能依靠。
它仅在单个连接数据库中有效,但是今天的单个连接数据库习惯于明天成为多个连接数据库。

看到: SHOW TABLE STATUS


5
我没有对此进行投票,但是尝试使用最后一个自动递增值的问题在于,无论您执行SELECT和随后的INSERT操作有多快,在使用它时它可能都不是最后一个。
麦克,

@Mike,如果在单个查询中完成怎么办?像insert into table_name (field1, field2) select 'constant', auto_increment from information_schema.tables where table_name = 'table_name'什么?我会在after insert触发器中使用更新last_insert_id(),不过……
binaryLV 2011年

1
@binaryLV:SELECT和INSERT之间的距离越小,值更改的机会就越小,但是并不能完全排除它。想象一下,每分钟有数千次命中的系统在数据库中-值更改的机会急剧增加。如果将表或行锁定作为单个查询来完成,则可能会阻止此操作,但这取决于数据库引擎的特定行为,而该行为可能没有得到很好的记录。UPDATE如果有的话,我会再跟一个。但是我宁愿在显示时将两者连接起来,并省去所有麻烦。
麦克,

3
SHOW TABLE STATUS预计,database nameFROM'table name pattern'LIKE
x-yuri 2014年

2
因为使用了缓存来从information_schema.tables中检索数据,所以该解决方案不再对mysql 8起作用。–
Bruno

14

这将为MySQL数据库返回自动增量值,而我没有与其他数据库进行检查。请注意,如果使用任何其他数据库,则查询语法可能会有所不同。

SELECT AUTO_INCREMENT 
FROM information_schema.tables
WHERE table_name = 'your_table_name'
     and table_schema = 'your_database_name';

SELECT AUTO_INCREMENT 
FROM information_schema.tables
WHERE table_name = 'your_table_name'
     and table_schema = database();

从information_schema.tables中选择AUTO_INCREMENT,其中table_name ='your_table_name'和table_schema ='your_database_name';
LJay

10

最佳答案是使用PHP MySQL_作为解决方案,以为我将共享一个更新的PHP MySQLi_解决方案以实现此目的。此示例中没有错误输出!

$db = new mysqli('localhost', 'user', 'pass', 'database');
$sql = "SHOW TABLE STATUS LIKE 'table'";
$result=$db->query($sql);
$row = $result->fetch_assoc();

echo $row['Auto_increment'];

找出表格中出现的下一个自动增量。


因为使用了缓存来从information_schema.tables中检索数据,所以该解决方案不再对mysql 8起作用。–
Bruno

9

在PHP中,您可以尝试以下操作:

$query = mysql_query("SELECT MAX(id) FROM `your_table_name`");
$results = mysql_fetch_array($query);
$cur_auto_id = $results['MAX(id)'] + 1;

要么

$result = mysql_query("SHOW TABLE STATUS WHERE `Name` = 'your_table_name'");
$data = mysql_fetch_assoc($result);
$next_increment = $data['Auto_increment'];

5
请记住,如果删除了具有最高ID的记录,则使用第一种方法,然后您将创建一个新记录,其ID与以前删除的ID相同。
汤姆·詹金森

如果先前的密钥在另一个表中使用并且仍保留在那里,那么您可能会得到非常奇怪的魔法
Tebe 2015年

如果您删除最后插入的记录,则第一个返回错误的ID,
Ali Parsa

6

解:

CREATE TRIGGER `IdTrigger` BEFORE INSERT ON `payments`
  FOR EACH ROW
BEGIN

SELECT  AUTO_INCREMENT Into @xId
    FROM information_schema.tables
    WHERE 
    Table_SCHEMA ="DataBaseName" AND
    table_name = "payments";

SET NEW.`payment_code` = CONCAT("sahf4d2fdd45",@xId);

END;

“ DataBaseName”是我们数据库的名称


5

简单的查询就可以了 SHOW TABLE STATUS LIKE 'table_name'



3

插入时不能使用ID,也不需要它。当您插入该记录时,MySQL甚至都不知道ID。您可以将其保存"sahf4d2fdd45"payment_code表中并使用,id然后payment_code再使用。

如果您确实需要Payment_code包含ID,则在插入后更新该行以添加ID。


+1使其更明确:如果您从列中获取“最新”值,则只能保证在获取该值的那一刻将其设为最新值。当您在后续插入中使用该值时,它可能不是最新值。对于自动递增列,在检索ID的时间与将其插入其他位置的时间之间总有可能添加了另一个值。如果要引用刚插入的行,则使用LAST_INSERT_ID()很好。如果您要确保唯一值,则不是。
麦克,

@ cularis,MySQL确实知道下一个auto_increment id,它在information_schema.tables表中列出。
约翰

1
@faressoft:如果要让付款代码包含唯一的字符串以及包含该付款代码的行的ID,请在检索该行时将二者结合在一起-可以使用SELECT ... CONCAT(payment_code, id)或在应用程序代码中。您甚至可以将包裹在SELECTVIEW,以便始终返回正确的值,而不必担心应用中每个SELECT中的CONCAT。
麦克,

3

下一个增量ID需要什么?

MySQL仅允许每个表一个自动递增字段,并且它还必须是保证唯一性的主键。

请注意,当您获得下一个插入ID时,使用该ID可能不可用,因为您拥有的值仅在该事务范围内。因此,根据数据库上的负载,该值可能在下一个请求进入时已被使用。

我建议您检查设计,以确保您无需知道接下来要分配的自动增量值


假定需要ID的应用程序不是一个好主意。目前有一些我正在处理的应用程序需要下一个增量ID,并且检索到的值没有被分配给另一个脚本的危险。
JG Estiot '16

3

我建议重新考虑您在做什么。我从未经历过需要特殊知识的单个用例。下一个id是一个非常特殊的实现细节,我不会指望它是ACID安全的。

进行一个简单的事务,该事务将使用最后一个ID更新您插入的行:

BEGIN;

INSERT INTO payments (date, item, method)
     VALUES (NOW(), '1 Month', 'paypal');

UPDATE payments SET payment_code = CONCAT("sahf4d2fdd45", LAST_INSERT_ID())
     WHERE id = LAST_INSERT_ID();

COMMIT;

我可以告诉一个这样的用例,我正在尝试诊断生产问题,因此我需要找出表中的最后一行是否真的是最后一行,或者是否在此之后添加了一行,然后以某种方式删除了该表其中有一个auto_increment字段,因此通过查找此信息,我可以得出该行是删除还是从不添加的结论。
乌斯曼

1
这可能也许对你的工作,但我不会依赖于因为我不认为你有对任何保证:dev.mysql.com/doc/refman/8.0/en/example-auto-increment.html “当AUTO_INCREMENT列是多列索引的一部分时,如果删除任何组中具有最大AUTO_INCREMENT值的行,则将重用AUTO_INCREMENT值。”
Markus Malkusch,

谢谢,有用的信息以及您共享链接中的auto_increment都可以通过手动插入数字来重置,因此是不可靠的。
Usman '18

2

您必须先连接到MySQL并选择一个数据库,然后才能执行此操作

$table_name = "myTable"; 
$query = mysql_query("SHOW TABLE STATUS WHERE name='$table_name'"); 
$row = mysql_fetch_array($query); 
$next_inc_value = $row["AUTO_INCREMENT"];  

2

使用“ mysql_insert_id()”。mysql_insert_id()作用于最后执行的查询,请确保在生成该值的查询之后立即调用mysql_insert_id()。

以下是使用示例:

<?php
    $link = mysql_connect('localhost', 'username', 'password');
if (!$link) {
    die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');

mysql_query("INSERT INTO mytable  VALUES('','value')");
printf("Last inserted record has id %d\n", mysql_insert_id());
    ?>

我希望上面的例子有用。


谢谢,我知道这一点。
Javed Multani先生,


1
SELECT id FROM `table` ORDER BY id DESC LIMIT 1

虽然我怀疑它的生产率,但是100%可靠


我也同意这是最简单的方法。不知道为什么您不赞成投票,但是我会以赞成投票抵消。
递归

我没有提到交易的必要性,如果您不将其包装在交易中,那么此代码就很糟糕,因为它可以满足实际加载的需要。
2016年

1
如果最新行被删除怎么办?还是删除了多个最新行?
利亚姆W

除非您明确指定非释放密钥,否则不会使用它
-Tebe

1

使用ravi404的答案:

CREATE FUNCTION `getAutoincrementalNextVal`(`TableName` VARCHAR(50))
    RETURNS BIGINT
    LANGUAGE SQL
    NOT DETERMINISTIC
    CONTAINS SQL
    SQL SECURITY DEFINER
    COMMENT ''
BEGIN

    DECLARE Value BIGINT;

    SELECT
        AUTO_INCREMENT INTO Value
    FROM
        information_schema.tables
    WHERE
        table_name = TableName AND
        table_schema = DATABASE();

    RETURN Value;

END

在插入查询中使用创建SHA1哈希。例如:

INSERT INTO
    document (Code, Title, Body)
VALUES (                
    sha1( getAutoincrementalNextval ('document') ),
    'Title',
    'Body'
);

这总是有效吗?如果两个插入物同时发生,是否存在比赛条件?
杰蒙斯(Jmons)2016年

0

@ ravi404的改进,以防您的自动增量偏移量不是1:

SELECT (`auto_increment`-1) + IFNULL(@@auto_increment_offset,1) 
FROM INFORMATION_SCHEMA.TABLES
WHERE table_name = your_table_name
AND table_schema = DATABASE( );

auto_increment-1):db引擎似乎总是认为偏移量为1。因此,您需要放弃此假设,然后添加@@ auto_increment_offset的可选值,或者默认为1:IFNULL(@@ auto_increment_offset,1)


0

对我来说,它很有效,而且看起来很简单:

 $auto_inc_db = mysql_query("SELECT * FROM my_table_name  ORDER BY  id  ASC ");
 while($auto_inc_result = mysql_fetch_array($auto_inc_db))
 {
 $last_id = $auto_inc_result['id'];
 }
 $next_id = ($last_id+1);


 echo $next_id;//this is the new id, if auto increment is on

$last_id只要可以,就不必重复分配DESC。您的while街区进行了大量无用的工作。
Tiw

是的,没错...我刚刚意识到它并不完美...:((如果它在之前被删除,那么结尾ID可以重复ID ... :(
Toncsiking

0

如果没有返回正确的AUTO_INCREMENT,请尝试:

ANALYZE TABLE `my_table`;
SELECT AUTO_INCREMENT FROM information_schema.TABLES WHERE (TABLE_NAME = 'my_table');

BD中的表清除缓存

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.