web-dev-qa-db-ja.com

php PDOは、プレースホルダー付きのバッチ複数行を挿入します

PHP PDOを使用して複数の挿入を行うことを探しています。

私が見つけた最も近い答えはこれです

how-to-insert-an-array-into-a-single-mysql-prepared-statement

ただし、指定された例では、??実際のプレースホルダーの代わりに。

私はPHPプレースホルダー用のdocサイトの例を見てきました

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

しかし、上記は機能しませんが、うまくいけば私が達成しようとしていることを実証します

20
Robbo_UK

まず第一に、 ?記号are実際のプレースホルダー(ほとんどのドライバーは、位置と名前付きのプレースホルダーの両方の構文を使用できます)。次に、準備済みステートメントは、SQLステートメントに生の入力を注入するためのツールにすぎません。SQLステートメント自体の構文には影響しません。必要な要素はすべて揃っています。

  • 1つのクエリで複数の行を挿入する方法
  • 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);
}
26

私はあなたがInnoDBを使用していると想定しているので、この回答はそのエンジン(または他のトランザクション対応エンジン、つまりMyISAMが含まれていないこと)に対してのみ有効です。

デフォルトでは、InnoDBは自動コミットモードで実行されます。つまり、各クエリは独自の包含トランザクションとして扱われます。

それを私たち人間が理解できるものに変換するには、発行するすべてのINSERTクエリは、クエリ情報を書き留めたことを確認することによって、ハードディスクに強制的にコミットさせることを意味します。 1秒あたりの入出力操作が低いために機械的なハードディスクが非常に遅いことを考えると(私が間違っていない場合、平均はIOが300です)、50 000クエリは非常に遅いことになります。

それで、あなたは何をしますか? 1回のトランザクションで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();
7
N.B.

N.Bが提供するソリューションの小さな変更
$ stmt-> execute()を呼び出す前にバインドする必要がある列が1つ以上ある可能性があるため、$ stmt-> execute()は内部ループの外側にある必要があります。バインドされた変数の数がトークンの数と一致しません。」.
2番目の「値」変数にドル記号がありませんでした。

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
Mudassar