MySQL LAST_INSERT_ID() used with multiple records INSERT statement
Yes. This behavior of last_insert_id()
is documented in the MySQL docs:
Important
If you insert multiple rows using a singleINSERT
statement,LAST_INSERT_ID()
returns the value generated for the first inserted row only. The reason for this is to make it possible to reproduce easily the sameINSERT
statement against some other server.
Insert n rows with LAST_INSERT_ID
What you show is the way I would do it. You can insert multiple rows using INSERT in the manner you show, by writing multiple row constructors after the VALUES keyword. If you do, you must include a value for all the columns named in your INSERT statement in every row constructor. Therefore you must reference the @post_id
variable in each row constructor.
If you really don't like to write @post_id
more than once, you could do something like this:
INSERT INTO POSTS_HASHTAGS_RELATION (post_id, hashtag_id)
SELECT @post_id, hashtag_id FROM (
SELECT 19 AS hashtag_id UNION SELECT 41 UNION SELECT 42 UNION ...
) AS t;
But that seems less clear and readable than the way you were doing it.
Re your comment:
I'm not a node.js programmer, but I've used the technique in other languages to build an SQL statement with a number of row constructors based on the input list. Proper query parameters can only be used in place of scalar values, not lists or expressions or identifiers or SQL keywords, etc. But I understand node.js does some extra string-substitution magic, so they're not really doing query parameters.
Suppose you had just done your INSERT into POSTS, you could capture the last insert id:
var postId = result.insertId;
Then create a partial INSERT statement for your next insert:
insert = 'INSERT INTO POSTS_HASHTAGS_RELATION (post_id, hashtag_id) VALUES';
You will need an array for the row constructors and an array for the parameters:
let rowConstructors = [];
let parameters = [];
hashtags.forEach(function (hashtag) {
rowConstructors.push('(?, ?)');
parameters.concat(postId, hashtag);
});
Now you have an array of row constructors, which toString()
will turn into a comma-separated string. And you have an array of values to pass as parameters.
connection.query(insert + rowConstructors.toString(),
parameters, function (error, results, fields) {
if (error) throw error;
// ...
});
I guess the .toString()
is optional, because the array should be coerced to a string automatically by concatenating it to the insert
string.
Again, I'm not a node.js programmer, so forgive me if there are errors or style problems. But that should give you the idea of this technique.
PDO - lastInsertId() for insert query with multiple rows
It's not possible. If you need generated ids for both rows - you need to perform 2 separated INSERT
Important If you insert multiple rows using a single INSERT statement,
LAST_INSERT_ID() returns the value generated for the first inserted
row only. The reason for this is to make it possible to reproduce
easily the same INSERT statement against some other server.
http://dev.mysql.com/doc/refman/5.5/en/information-functions.html#function_last-insert-id
Mysql mulitple row insert-select statement with last_insert_id()
For the last query, use this
INSERT INTO dbNEW.`user` (userID, entityID, other)
SELECT user_id, entityID, other
FROM
(
SELECT user_id, @key + @rn entityID, other, @rn := @rn + 1
FROM (select @rn:=0) x, dbOLD.`user`
order by user_id
) y;
The LAST_INSERT_ID() in MySQL is the FIRST id created in a batch, unlike SCOPE_IDENTITY() in SQL Server which is the LAST id. Since it is the first, we increment each row using the variable @rn, starting at addition=0
for the first row.
insert many rows, LAST_INSERT_ID return 1
The MySQL documentation clearly explains this behavior:
With no argument, LAST_INSERT_ID() returns a BIGINT UNSIGNED (64-bit) value representing the first (emphasis mine) automatically generated value successfully inserted for an AUTO_INCREMENT column as a result of the most recently executed INSERT statement. The value of LAST_INSERT_ID() remains unchanged if no rows are successfully inserted.
The first value generated by the auto increment sequence in the insert was 1, not 2 or 3, so the value 1 gets returned.
I think the confusion you have is around the name LAST_INSERT_ID
. The "last" part refers to the most recent insert statement, not the most recent id
value within that insert.
LAST_INSERT_ID( ) returning multiple rows of 0?
LAST_INSERT_ID()
returns the id of the last inserted row and is not bound to any table. So if you create a new row:
INSERT INTO table VALUES('a', 'b', 'c');
It will return the last id (whatever value the new primary key has).
SELECT LAST_INSERT_ID();
=> 123
For details, please take a look at the manual:
LAST_INSERT_ID() (with no argument) returns a BIGINT (64-bit) value representing the first automatically generated value that was set for an AUTO_INCREMENT column by the most recently executed INSERT statement to affect such a column. For example, after inserting a row that generates an AUTO_INCREMENT value, you can get the value like this:
If you just want to get last ID in a table, you can do it like this:
SELECT id FROM table ORDER BY id DESC LIMIT 1;
Insert multiple rows from a select and put the generated IDs into other table
You can assume that a multi-row INSERT generates consecutive auto-increment id's, unless innodb_auto_inc_lock_mode=2
. See https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html
LAST_INSERT_ID() will tell you the first id generated by the insert, and the others will each be 1 greater, as many as the number of rows inserted.
Then you can UPDATE alpha to set these, but be sure to use ORDER BY to specify both the order of copying and the order of UPDATE so they remain the same.
INSERT INTO beta (type_info)
SELECT type_info FROM alpha
WHERE beta_id IS NULL
ORDER BY id;
SET @id = LAST_INSERT_ID()-1;
UPDATE alpha
SET beta_id=(@id := @id + 1)
WHERE beta_id IS NULL
ORDER BY id;
Related Topics
Oracle: How to Get Percent of Total by a Query
Group Data by the Change of Grouping Column Value in Order
Table in Excel from SQL Server Stored Procedure with Parameter Field in Workbook
How to Get Week Start and End Date String in Postgresql
How to List User Defined Types in a SQL Server Database
How to Count Rows That Have the Same Values in Two Columns (Sql)
Concatenate/Merge Array Values During Grouping/Aggregation
Postgresql Not Ilike Clause Does Not Include Null String Values
Sequentially Number Rows by Keyed Group in SQL
Sqlite: Preventing Duplicate Rows
Need a Tool to Automatically Indent and Format SQL Server Stored Procedures
Entity Framework: How to Properly Handle Exceptions That Occur Due to SQL Constraints
How to Select Records Only from Yesterday
Convert Access Transform/Pivot Query to SQL Server
SQL Code to Insert Multiple Rows in Ms-Access Table