Объемные Параметризованные Вставки


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

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

$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 оператор с 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);
}

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

Author: Community, 2011-01-11

2 answers

Что ж, у вас есть три варианта.

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

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

 6
Author: ircmaxell, 2011-01-11 16:02:07

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

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

 2
Author: Stephen, 2011-01-11 16:33:13