如何将多行插入 MySQL 表并返回新 ID?
通常我可以在 MySQL 表中插入一行并获取 last_insert_id
。但现在,我想将许多行批量插入到表中并获取 ID 数组。有谁知道我该怎么做?
类似的问题还有一些,但又不完全一样。我不想将新 ID 插入任何临时表;我只想取回 ID 数组。
Normally I can insert a row into a MySQL table and get the last_insert_id
back. Now, though, I want to bulk insert many rows into the table and get back an array of IDs. Does anyone know how I can do this?
There are some similar questions, but they are not exactly the same. I don't want to insert the new ID to any temporary table; I just want to get back the array of IDs.
Can I retrieve the lastInsertId from a bulk insert?
Mysql mulitple row insert-select statement with last_insert_id()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
旧线程,但只是研究了这个,所以这里是:如果您在最新版本的 MySQL 上使用 InnoDB,您可以使用
LAST_INSERT_ID()
和ROW_COUNT()< 获取 ID 列表/代码>。
InnoDB 在进行批量插入时保证自动增量的顺序号,前提是 innodb_autoinc_lock_mode 设置为 0(传统)或 1(连续)。
因此,您可以从
LAST_INSERT_ID()
获取第一个 ID,并通过添加ROW_COUNT()-1
获取最后一个 ID。Old thread but just looked into this, so here goes: if you are using InnoDB on a recent version of MySQL, you can get the list of IDs using
LAST_INSERT_ID()
andROW_COUNT()
.InnoDB guarantees sequential numbers for AUTO INCREMENT when doing bulk inserts, provided
innodb_autoinc_lock_mode
is set to 0 (traditional) or 1 (consecutive).Consequently you can get the first ID from
LAST_INSERT_ID()
and the last by addingROW_COUNT()-1
.我认为可以做到的唯一方法是为插入的每组行存储唯一标识符(guid)
然后选择行 ID。
例如:
您还可以使用
uuid()
在数据库中生成guidThe only way I can think it could be done is if you store a unique identifier for each set of rows inserted (guid)
then select the row ids.
e.g:
You could also generate the guid in the database by using
uuid()
假设我们有一个名为 temptable 的表,有两个列 uid,col1,其中 uid 是一个自动递增字段。执行如下操作将返回结果集中所有插入的 id。您可以循环遍历结果集并获取您的 id。我意识到这是一篇旧文章,这个解决方案可能并不适用于所有情况。但对于其他人来说可能是这样,这就是我回复它的原因。
Lets assume we have a table called temptable with two cols uid, col1 where uid is an auto increment field. Doing something like below will return all the inserted id's in the resultset. You can loop through the resultset and get your id's. I realize that this is an old post and this solution might not work for every case. But for others it might and that's why I'm replying to it.
我不确定自动增量值是否会将项目增加 1。如果您的数据库具有 Master // Master 复制并解决 auto_increment 重复排除问题,将会出现巨大的问题。 AI将是+2而不是+1,而且如果再多一个大师,它也会变成+3。因此,请继续关注诸如 AUTO_INCRMENT 正在上升之类的事情,因为 1 会杀死您的项目。
我只看到一些好的选择来做到这一点。
这个 SQL 片段对于多个 master 来说不会有任何问题,并且会给出良好的结果,直到您只需要插入记录。在没有事务的多个请求上可以捕获其他插入记录。
(如果您还需要通过 DUPLICATE KEY UPDATE 更新记录)您将需要稍微重构数据库,SQL 将如下所示(对于事务安全,并且一个连接内没有事务。)
这两种情况对于跨国都是安全的。第一个将仅显示插入的记录,第二个将向您提供所有更新的记录。
即使使用 INSERT IGNORE ,这些选项也将起作用...
I wouldn't be sure that auto increment value will increase item by 1. and there will be huge problems if your DB will have Master // Master replication and to resolve auto_increment duplicate exclusion. AI will be +2 instead of +1, also if there will be one more master it will come to +3. so relay on thing like AUTO_INCREMENT is going up for 1 is killing your project.
I see only some good options to do that.
this SQL snippet will have no problems with multiple masters and give good results until you will need only inserted records. on multiple requests without transactions can catch other inserts records.
(if you will need also updated records by DUPLICATE KEY UPDATE) you will need to refactor database a bit and SQL will look like next, (safe for transactions and no transactions inside one connection.)
both cases are safe to transnational. first will show you only inserted records and second will give you all records even updated.
also those options will work even with INSERT IGNORE ...
值得注意的是,如果您将
innodb_autoinc_lock_mode
设置为2
,只需在插入之前锁定表即可实现 @Dag Sondre Hansen 的答案。这是一个小提琴演示: https://www.db-fiddle.com/f/ahXAhosYkkRmwqR9Y4mAsr /0
It's worth noting that @Dag Sondre Hansen's answer can also be implemented in case you have
innodb_autoinc_lock_mode
set to2
by simply locking the table before insert.Here's a fiddle demonstrating: https://www.db-fiddle.com/f/ahXAhosYkkRmwqR9Y4mAsr/0
这个线程很旧,但所有这些解决方案都没有帮助我,所以我想出了自己的解决方案。
首先,计算要插入的行数
假设我们需要添加 5 行:
然后使用刚刚选择的 auto_increment 执行下一个查询:
最后执行您的 操作inserts
使用保留的自增范围以 id 进行插入。
警告:此解决方案需要提升对表的访问级别。但通常批量插入是由 crons 和导入器脚本运行的,无论如何都可能使用特殊访问权限。您不会仅将其用于几次插入。
如果您使用 ON DUPLICATE KEY UPDATE,这可能会留下未使用的 ID。
This thread is old but all these solutions did not help me so I came up with my own.
First, count how many rows you want to insert
let's say we need to add 5 rows:
then use the auto_increment just selected to do next query:
Finally do your inserts
Use the reserved autoincrement range to insert with id.
Warning: this solution requires elevated access level to the tables. But usually bulk inserts are run by crons and importer scripts and what not that may use special access anyway. You would not use this for just a few inserts.
This may leave unused id's if you use ON DUPLICATE KEY UPDATE.
对于任何使用 java 和 JDBC 的人来说,这是可能的。我通过批量插入获取 ID,如下所示:
来源:“使用 MySQL,我可以通过这种方式使用 JDBC 来实现:” - Plap - https://groups.google.com/g/jdbi/c/ZDqnfhK758g?pli=1
我必须将其实际添加到我的 JDBC url:rewriteBatchedStatements=true。否则,实际插入将作为单独的行显示在 mysql“常规查询日志”中。插入 7000 行后,常规插入需要 2 分 11 秒,没有重写时需要 46 秒,而重写时需要 1.1 秒。而且,它不会阻止其他人的插入(我测试过)。当我插入 200k 行时,它会将它们分组为每行约 36k 行,即
insert into abc(..) value(..),(..),(..)...
。我实际上使用的是 JDBCTemplate 所以访问PreparedStatement的方法是:
For anyone using java with JDBC, it is possible. I am getting ids back with batch-insert doing it like this:
Source: "Using MySQL I can do it with JDBC this way:" - Plap - https://groups.google.com/g/jdbi/c/ZDqnfhK758g?pli=1
I have to actually add this to my JDBC url: rewriteBatchedStatements=true. Or else the actual inserts show up in the mysql "general query log" as separate rows. With 7000 rows inserted, I got 2m11s for regular inserts, 46s without rewrite.. on and 1.1s with rewrite.. on. Also, it does not make other people's inserts block (I tested that). When I inserted 200k rows, it grouped them into about 36k per line ie
insert into abc(..) values(..),(..),(..)...
.I am actually using JDBCTemplate so the way to access the PreparedStatement is:
我认为您必须处理应用程序中的交易 id 或应用程序中的项目 id 才能完美地完成此操作。
假设所有插入都成功(!),一种可行的方法如下:
然后,您可以通过循环获取受影响行数的插入 id,从 lastid (这是第一个插入的 id)开始的批量插入)。
因此,我检查它工作完美..只是要小心,例如 HeidiSQL 不会返回 ROW_COUNT() 的正确值,可能是因为它是一个蹩脚的 GUI 做随机的事情,我们不会问它 - 但它是完全正确的命令行或 PHP mysqli -
在 PHP 中,它看起来像这样(local_sqle 是对 mysqli_query 的直接调用,local_sqlec 是对 mysqli_query + 将结果集转换为 PHP 数组的调用):
原因查询被分开是因为我不会使用我自己的函数获得结果,如果您使用标准函数执行此操作,您可以将其放回一个语句中,然后检索您需要的结果(它应该是结果号 2 -假设您使用一个可以处理多个结果集/查询的扩展)。
I think you will have to either handle the transaction id in your application, or the item id in your application in order to do this flawlessly.
One way to do this which could work, assuming that all your inserts succeed (!), is the following :
You can then get the inserted id's with a loop for the number of affected rows, starting with lastid (which is the first inserted id of the bulk insert).
And thus, i checked it works perfectly .. just be careful that HeidiSQL for example will not return the correct value for ROW_COUNT(), probably because it's a crappy GUI doing random shit we don't ask it - however it's perfectly correct from either command line or PHP mysqli -
In PHP it looks like this (local_sqle is a straight call to mysqli_query, local_sqlec is a call to mysqli_query + convert resultset to PHP array) :
The reason the queries are separated is because I wouldn't otherwise get my result using my own functions, if you do this with standard functions, you can put it back in one statement and then retrieve the result you need (it should be result number 2 - assuming you use an extension which handles more than one result set / query).