Я хочу сделать несколько вложений с помощью 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();
Однако вышеизложенное не работает, но, надеюсь, продемонстрирует, что я пытаюсь достичь
Прежде всего ?
символы являются реальными держателями мест (большинство драйверов позволяют использовать как синтаксисы, так и позиционные и названные владельцы мест). Во-вторых, подготовленные утверждения – это не что иное, как инструмент для ввода исходных данных в 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, который вы выдаете, заставит жесткий диск зафиксировать его, подтвердив, что он записал информацию о запросе. Учитывая, что механические жесткие диски очень медленны, поскольку их скорость ввода-вывода в секунду низкая (если я не ошибаюсь, среднее значение – 300ish 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();
Небольшие изменения в решении, предоставляемые 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->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); }
Если у вас возникнут какие-либо проблемы с этим рекомендуемым способом, вы должны задать вопрос, описывающий эти определенные проблемы.