簡體   English   中英

php PDO使用占位符插入批處理多行

[英]php PDO insert batch multiple rows with placeholders

我希望使用PHP PDO進行多次插入。

我找到的最接近的答案是這一個

如何對嵌件的陣列-進入-一個單MySQL的准備語句

然而,給出的例子使用?? 而不是真正的占位符。

我查看了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();

然而,上述情況不起作用,但希望能夠展示我想要實現的目標

首先, ? 符號真正的占位符(大多數驅動程序允許使用語法,位置和命名占位符)。 其次,准備好的語句只不過是將原始輸入注入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);
}

我假設您正在使用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();

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

你的代碼實際上沒問題,但在$stmt->bindParam(":$column", value);遇到了問題$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();
} 

在循環內移動執行。

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

如果您遇到這種推薦方式的任何問題,您必須提出一個問題,描述這些問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM