我希望使用PHP PDO进行多次插入。
我找到的最接近的答案就是这个
how-to-insert-an-array-into-a-single-mysql-prepared-statement
然而,给出的例子使用??而不是真正的占位符。
我查看了PHP文档站点上的占位符
的示例php.net pdo.prepared-statements
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
现在让我说我想实现上述但是使用数组
$valuesToInsert = array(
0 => array('name' => 'Robert', 'value' => 'some value'),
1 => array('name' -> 'Louise', 'value' => 'another value')
);
我如何使用PDO和每次交易多次插入?
我想它会以循环开始?
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
foreach($valuesToInsert as $insertRow){
// now loop through each inner array to match binded values
foreach($insertRow as $column => value){
$stmt->bindParam(":{$column}", value);
}
}
$stmt->execute();
然而,上述情况不起作用,但希望能够展示我想要实现的目标
答案 0 :(得分:25)
首先,?
符号是真正的占位符(大多数驱动程序允许使用语法,位置和命名占位符)。其次,准备好的语句只不过是将原始输入注入SQL语句的工具 - SQL语句本身的语法不受影响。您已经拥有了所需的所有元素:
将它们全部合并起来相当简单:
$sql = 'INSERT INTO table (memberID, programID) VALUES ';
$insertQuery = array();
$insertData = array();
$n = 0;
foreach ($data as $row) {
$insertQuery[] = '(:memberID' . $n . ', :programID' . $n . ')';
$insertData['memberID' . $n] = $memberid;
$insertData['programID' . $n] = $row;
$n++;
}
if (!empty($insertQuery)) {
$sql .= implode(', ', $insertQuery);
$stmt = $db->prepare($sql);
$stmt->execute($insertData);
}
答案 1 :(得分:7)
我假设您正在使用InnoDB,因此此答案仅对该引擎(或任何其他具有交易功能的引擎有效,意味着不包括MyISAM)。
默认情况下,InnoDB以自动提交模式运行。这意味着每个查询都被视为自己包含的事务。
要将其转换为我们凡人可以理解的内容,这意味着您发出的每个INSERT查询都会强制硬盘通过确认它写下查询信息来提交它。 考虑到机械硬盘如何超慢,因为它们每秒的输入输出操作很低(如果我没有记错,平均值是300的IO),这意味着你的5万个查询将会 - 超级慢。
那你做什么?您在一次交易中提交所有50k查询。它可能不是用于各种目的的最佳解决方案,但它会很快。
你这样做:
$dbh->beginTransaction();
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
foreach($valuesToInsert as $insertRow)
{
// now loop through each inner array to match bound values
foreach($insertRow as $column => value)
{
$stmt->bindParam(":$column", value);
$stmt->execute();
}
}
$dbh->commit();
答案 2 :(得分:1)
N.B提供的解决方案略有修改
$ stmt-> execute()应该在内部循环之外,因为在调用$ stmt-> execute()之前你可能有一个或多个需要绑定的列,否则你会得到异常"无效参数号:绑定变量的数量与令牌的数量不匹配"。
第二"价值"变量缺少美元符号。
function batchinsert($sql,$params){
try {
db->beginTransaction();
$stmt = db->prepare($sql);
foreach($params as $row)
{
// now loop through each inner array to match bound values
foreach($row as $column => $value)
{
$stmt->bindParam(":$column", $value);
}
$stmt->execute();
}
db->commit();
} catch(PDOExecption $e) {
$db->rollback();
}
}
测试:
$sql = "INSERT INTO `test`(`name`, `value`) VALUES (:name, :value)" ;
$data = array();
array_push($data, array('name'=>'Name1','value'=>'Value1'));
array_push($data, array('name'=>'Name2','value'=>'Value2'));
array_push($data, array('name'=>'Name3','value'=>'Value3'));
array_push($data, array('name'=>'Name4','value'=>'Value4'));
array_push($data, array('name'=>'Name5','value'=>'Value5'));
batchinsert($sql,$data);
答案 3 :(得分:-1)
您的代码确实没问题,但在$stmt->bindParam(":$column", value);
中遇到问题应该是$stmt->bindValue(":{$column}", $value);
并且它会完美运行。这将有助于其他人。
完整代码:
foreach($params as $row)
{
// now loop through each inner array to match bound values
foreach($row as $column => $value)
{
$stmt->bindValue(":{$column}", $value); //EDIT
}
// Execute statement to add to transaction
$stmt->execute();
}
答案 4 :(得分:-4)
在循环内移动执行。
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
foreach($valuesToInsert as $insertRow)
{
$stmt->execute($insertRow);
}
如果您在使用此推荐方式时遇到任何问题,则必须提出问题,并说明这些问题。