Массовые параметризованные вставки - PullRequest
10 голосов
/ 11 января 2011

Я пытаюсь переключить некоторые жестко запрограммированные запросы для использования параметризованных входов, но я столкнулся с проблемой: как вы форматируете ввод для параметризованных массовых вставок?

В настоящее время код выглядит так:

$data_insert = "INSERT INTO my_table (field1, field2, field3) ";
$multiple_inserts = false;
while ($my_condition)
{
    if ($multiple_inserts)
    {
        $data_insert .= " UNION ALL ";
    }

    $data_insert .= " SELECT myvalue1, myvalue2, myvalue3 ";
}

$recordset = sqlsrv_query($my_connection, $data_insert);

Потенциальное решение (изменено с Как вставить массив в один оператор MySQL Prepared с PHP и PDO ) выглядит так:

$sql = 'INSERT INTO my_table (field1, field2, field3) VALUES ';
$parameters = array();
$data = array();
while ($my_condition)
{
    $parameters[] = '(?, ?, ?)';
    $data[] = value1;
    $data[] = value2;
    $data[] = value3;
}

if (!empty($parameters)) 
{
    $sql .= implode(', ', $parameters);
    $stmt = sqlsrv_prepare($my_connection, $sql, $data);
    sqlsrv_execute($stmt);
}

Есть ли лучший способ выполнить массовую вставку с параметризованными запросами?

Ответы [ 2 ]

6 голосов
/ 11 января 2011

Ну, у вас есть три варианта.

  1. Построить один раз - выполнить несколько. По сути, вы готовите вставку один раз для одной строки, а затем выполняете цикл по строкам, выполняющим ее. Поскольку расширение SQLSERVER не поддерживает повторную привязку запроса после его подготовки (необходимо выполнить грязных хаков со ссылками ), что может быть не лучшим вариантом.

  2. Построить один раз - выполнить один раз. По сути, вы строите одну гигантскую вставку, как вы сказали в своем примере, привязываете ее один раз и выполняете. Это немного грязно и упускает некоторые преимущества, которые дает подготовленный запрос. Однако, из-за требования ссылок из Варианта 1, я бы сделал это. Я думаю, что лучше составить гигантский запрос, чем зависеть от ссылок на переменные.

  3. Создать несколько - выполнить несколько. В основном, возьмите метод, который вы делаете, и настройте его, чтобы заново подготовить запрос для каждого такого количества записей. Это предотвращает слишком большие запросы и «пакетирует» запросы. Вот как то так:

    $sql = 'INSERT INTO my_table (field1, field2, field3) VALUES ';
    $parameters = array();
    $data = array();
    
    $execute = function($params, $data) use ($my_connection, $sql) {
        $query = $sql . implode(', ', $parameters);
        $stmt = sqlsrv_prepare($my_connection, $query, $data);
        sqlsrv_execute($stmt);
    }
    
    while ($my_condition) {
        $parameters[] = '(?, ?, ?)';
        $data[] = value1;
        $data[] = value2;
        $data[] = value3;
        if (count($parameters) % 25 == 0) {
            //Flush every 25 records
            $execute($parameters, $data);
            $parameters = array();
            $data = array();
        }
    }
    if (!empty($parameters))  {
        $execute($sql, $parameters, $data);
    }
    

Любой метод будет достаточным. Делайте то, что, по вашему мнению, лучше всего соответствует вашим требованиям ...

2 голосов
/ 11 января 2011

Почему бы просто не использовать метод «подготовить один раз, выполнить несколько». Я знаю, что вы хотите, чтобы все это или не сработало, или все сработало, но это не совсем сложно с транзакциями:

http://www.php.net/manual/en/pdo.begintransaction.php

http://www.php.net/manual/en/pdo.commit.php

http://www.php.net/manual/en/pdo.rollback.php

...