2013-02-25 162 views
18

我正在寻找使用PHP PDO进行多次插入。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(); 

然而上述不工作,但希望能证明什么IM努力实现

+2

你需要在循环中执行。否则你只是覆盖绑定的参数,并最终只绑定LAST值。 – 2013-02-25 15:04:27

+1

但是,如果我执行那么这将做一次数据库事务一行?我试图批量执行 – 2013-02-25 15:05:21

+0

是的,但如果你想模拟mysql扩展的'insert ... values(...),(...),(...)'插入语法,这是不是你怎么去做的。您必须预先构建一个查询语句,该语句为您插入的每组值创建一个占位符,然后进行准备,绑定参数,然后执行。您最终只需多次运行一个准备好的插入程序即可完成同样的工作。 – 2013-02-25 15:07:36

回答

24

首先,?符号真正的占位符(大多数司机允许使用两种语法,位置和命名占位)。其次,准备好的语句不过是将原始输入注入SQL语句的工具 - 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); 
} 
-4

移动的循环内执行。

$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)"); 
foreach($valuesToInsert as $insertRow) 
{ 
    $stmt->execute($insertRow);  
} 

如果您遇到这种这种推荐的方式有任何问题,你要问一个问题,这说明某些问题。

+1

我不认为上面是批量看起来像它一次做一个吗? – 2013-02-25 15:21:49

+0

这不是批量插入,你很清楚地重复使用每行多次相同的SQL语句,但它仍然一次只进行一次插入。 – 2017-06-06 13:47:30

7

我假设你正使用InnoDB所以这个答案只适用于发动机(或任何其他交易功能的引擎,这意味着MyISAM的ISN包括在内)。

默认InnoDB以自动提交模式运行。这意味着每个查询都被视为自己包含的事务。

要将其转换为我们凡人能够理解的事物,这意味着您发出的每个INSERT查询都会强制硬盘通过确认它记下查询信息来提交它。 考虑到机械硬盘由于每秒钟的输入输出操作很低(如果我没有弄错,平均值是300个IO),它的速度超慢,这意味着你的50,000个查询将会 - 很好,超级慢。

那么你会怎么做?您在单个交易中完成所有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(); 
+0

我有大约50k行插入,并打算做25批处理。我会尝试这个例子,因为它看起来可能是我在找什么。 – 2013-02-25 15:39:27

+1

这个答案是正确的,但它并没有提到MySQL的多插入语法,就我的经验而言,真正能够加快大批量的操作。 – 2013-02-26 11:06:37

+0

为了获得最佳性能,'LOAD DATA INFILE'仍然是最快的选项,构建一个与'LOAD DATA INFILE'一起使用的文件应该相当简单。我忘了将其添加到答案中,正如@ÁlvaroG.Vicario所述 - “INSERT INTO .... VALUES..'比在循环中执行预备语句更快。 – 2013-02-26 11:38:11

1

在溶液中一点点修改由NB提供
$ 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); 
-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(); 
} 
+0

这部分语法没有任何问题。你的建议是多余的和误导性的。 – 2016-03-24 14:01:24