Kirkland Kirkland - 1 month ago 5
MySQL Question

PHP for a single MySQL multi-row INSERT with LAST_INSERT_ROW for each row?

Skip to "My Code" at the bottom of the question to get straight to the point.




$con = mysql_connect('localhost', 'mysql_user', 'mysql_password');





General Examples:

Multiple query strings can be executed within a single
mysql_query
, like this...

mysql_query("
INSERT INTO table_one (a,b,c) VALUES (1,2,3);
INSERT INTO table_two (x,y,z) VALUES (7,8,'a text value');
", $con);


Multiple rows can be added to each query string, like this...

mysql_query("
INSERT INTO table_one (a,b,c) VALUES (1,2,3), (2,3,1), (3,1,2);
INSERT INTO table_two (x,y,z) VALUES (7,8,9), (8,9,7), (9,7,8);
", $con);


With an array of values, like this...

$array(
[0] => array(1,2,3),
[1] => array(2,'text',1),
[2] => array(3,1,2)
);


...a query string can be dynamically created using a loop, like this...

$a = "INSERT INTO table_one (a,b,c) VALUES ";
foreach($array as $val){
$a .= "(". implode(",",$val) ."),";
}
$a = trim($a, ",") . ";";





The Question:

How to write a single MySQL query that executes multiple INSERT query strings, each with multiple rows, so that each row inserted by the second query string can reference the corresponding row inserted by the first query string. Thus
$var
in this snippet would correspond to the auto_increment row ID of the first INSERT.

mysql_query("
INSERT INTO table_one (a,b,c) VALUES (1,2,3), (2,3,1), (3,1,2);
INSERT INTO table_two (x,y,z) VALUES ($var,8,9), ($var,9,7), ($var,7,8);
", $con);





My Code:

This is a simplified version of my code...

$q1 = "INSERT INTO `table_one` (t1c1,t1c2) VALUES ";
$q2 = "INSERT INTO `table_two` (t2c1,t2c2,t2c3) VALUES ";

foreach($array as $item){
$q1 .= "('". $item ."','blah'),";
$q2 .= "('". $row_ID_from_first_insert ."','something','whatever'),";
}

$q1 = trim($q1,",") .";";
$q2 = trim($q2,",") .";";
$q = $q1.$q2;

mysql_query($q, $this->connect);


What is a safe way to generate
$row_ID_from_first_insert
?

From my understanding using
LAST_INSERT_ID()
in the query string will not work because when multiple rows are inserted with a single query string it only returns the first inserted row ID. Is it safe to use
LAST_INSERT_ID()+1
where
1
is replaced with a incremental variable in the foreach loop? What if multiple submits occur at the same time from different users?

Answer

Generally you'll have to fetch back out the id values of the inserted rows. This is unless you can create another key that is used in place of that which can be procedurally generated in advance.

While INSERT statements with multiple rows is significantly faster, the price you pay is a lack of precision. If your id values are issued sequentially, which is the default behavior, then you can be reasonably assured that the LAST_INSERT_ID() represents the ID of the first row inserted, so you could perhaps calculate the ID of the rows using the method you propose, though starting at index 0.

Remember that multiple submissions do not affect the LAST_INSERT_ID() result because this value is per-connection. It is only changed if you perform a subsequent query on the same database handle. Operations in other requests will not affect it.

Databases that are clustered or multi-master may issue non-sequential identifiers in which case this won't work. This is also unreliable in an INSERT IGNORE situation where the number of rows actually inserted could be less than the number of rows provided.

Comments