23

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

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

単一の mysql 準備済みステートメントに配列を挿入する方法

ただし、与えられた例では ?? を使用しています。実際のプレースホルダーの代わりに。

プレースホルダーについては、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();

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

4

5 に答える 5

30

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

  • 単一のクエリで複数の行を挿入する方法
  • SQL を動的に生成する方法
  • 名前付きプレースホルダーで準備済みステートメントを使用する方法。

それらをすべて組み合わせるのはかなり簡単です。

$sql = 'INSERT INTO table (memberID, programID) VALUES ';
$insertQuery = [];
$insertData = [];
$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);
}
于 2013-02-25T15:17:28.360 に答える
8

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

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

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

それで、あなたは何をしますか?1 回のトランザクションで 50,000 件のクエリをすべてコミットします。さまざまな目的に最適なソリューションではないかもしれませんが、高速です。

次のようにします。

$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();
于 2013-02-25T15:26:52.827 に答える
1


$stmt->execute() を呼び出す前にバインドする必要がある列が 1 つ以上ある可能性があるため、NB $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);
于 2015-06-01T15:44:00.620 に答える
-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();
} 
于 2016-03-24T13:36:08.793 に答える
-4

実行をループ内に移動します。

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

このような推奨される方法で問題が発生した場合は、これらの問題について説明して質問する必要があります。

于 2013-02-25T15:17:23.337 に答える