PHP 用于单个 MySQL 多行 INSERT,每行带有 LAST_INSERT_ROW?

Posted

技术标签:

【中文标题】PHP 用于单个 MySQL 多行 INSERT,每行带有 LAST_INSERT_ROW?【英文标题】:PHP for a single MySQL multi-row INSERT with LAST_INSERT_ROW for each row? 【发布时间】:2012-10-24 21:37:45 【问题描述】:

跳到问题底部的“我的代码”,直奔主题。


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


一般示例:

多个查询字符串可以在单个mysql_query 中执行,像这样...

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);

每个查询字符串可以添加多行,像这样...

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);

有一个值数组,像这样...

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

...可以使用循环动态创建查询字符串,如下所示...

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

$a = trim($a, ",") . ";";

问题:

如何编写执行多个 INSERT 查询字符串的单个 MySQL 查询,每个查询字符串都有多行,以便第二个查询字符串插入的每一行都可以引用第一个查询字符串插入的相应行。因此,此 sn-p 中的 $var 将对应于第一个 INSERT 的 auto_increment 行 ID。

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);

我的代码:

这是我的代码的简化版本...

$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);

生成$row_ID_from_first_insert 的安全方法是什么?

据我了解,在查询字符串中使用 LAST_INSERT_ID() 将不起作用,因为当使用单个查询字符串插入多行时,它仅返回第一个插入的行 ID。使用LAST_INSERT_ID()+1 是否安全,其中1 被foreach 循环中的增量变量替换?如果来自不同用户的多个提交同时发生怎么办?

【问题讨论】:

请不要在新应用程序中使用mysql_query。它很难正确使用,并且可能导致SQL injection bugs 出现严重 问题。学习 PDO 或 mysqli 只需要很短的时间,并且两者都大大简化了编写正确、安全的 SQL 接口代码的过程。 【参考方案1】:

通常,您必须取回插入行的id 值。除非您可以创建另一个密钥来代替可以提前通过程序生成的密钥。

虽然具有多行的INSERT 语句明显更快,但您付出的代价是缺乏精确度。如果您的 id 值是按顺序发出的,这是默认行为,那么您可以合理地确定 LAST_INSERT_ID() 代表插入的第一行的 ID,因此您可以使用您的方法计算行的 ID建议,虽然从索引 0 开始。

请记住,多次提交不会影响LAST_INSERT_ID() 结果,因为此值是针对每个连接的。仅当您对同一数据库句柄执行后续查询时,它才会更改。其他请求中的操作不会影响它。

集群或多主数据库可能会发出非顺序标识符,在这种情况下这将不起作用。这在INSERT IGNORE 的情况下也是不可靠的,实际插入的行数可能少于提供的行数。

【讨论】:

【参考方案2】:

LAST_INSERT_ID() 是在每个成功查询结束时从同一连接句柄生成的。因此,您的示例代码不会为您提供您正在寻找的结果。见下文:

mysql_query("
    INSERT INTO table_two (x,y,z) VALUES (LAST_INSERT_ID(),8,9), (LAST_INSERT_ID(),9,7), (LAST_INSERT_ID(),7,8);
", $con);

上面的结果将是(其中 x 是 LAST_INSERT_ID() 产生的值):

 x    y    z
 5    8    9
 5    9    7
 5    7    8

要接收您寻求的结果,使用您在示例中使用的相同格式(我不建议您使用 sql 注入的风险 - 改用 mysqli) 您可以这样做:

 mysql_query("
    INSERT INTO table_two (x,y,z) VALUES (LAST_INSERT_ID(),8,9);
    INSERT INTO table_two (x,y,z) VALUES (LAST_INSERT_ID(),9,7);
    INSERT INTO table_two (x,y,z) VALUES (LAST_INSERT_ID(),7,8); 
", $con);

这将为您提供(其中 x 是 LAST_INSERT_ID() 产生的值):

 x    y    z
 5    8    9
 6    9    7
 7    7    8

【讨论】:

以上是关于PHP 用于单个 MySQL 多行 INSERT,每行带有 LAST_INSERT_ROW?的主要内容,如果未能解决你的问题,请参考以下文章

php - 如何生成 MySQL INSERT 语句以使用数组中的多行填充表

使用单个 INSERT 语句将多行插入到表中

在单个 INSERT 查询中插入多行会保证顺序自动递增主键吗?

如何在 PHP 中从 AUTO_INCREMENT 列中为每行检索生成的 PRIMARY KEY,并在 MySQL 中插入多行?

Oracle 插入数据

mysq