Подтвердить что ты не робот

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

Однако вышеизложенное не работает, но, надеюсь, продемонстрирует, что im пытается достичь

4b9b3361

Ответ 1

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

Ответ 2

Я предполагаю, что вы используете 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();

Ответ 3

Небольшие изменения в решении, предоставленные N.B
$ 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);

Ответ 4

Ваш код был в порядке, но возникла проблема в $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();
} 

Ответ 5

Переместить выполнение внутри цикла.

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

Если у вас возникли проблемы с этим рекомендуемым способом, вы должны задать вопрос, описывающий эти определенные проблемы.