Подготовленный оператор не может выполняться несколько раз с целыми значениями

Как правильно выполнить повторный запуск подготовленного оператора с использованием разных целых значений?

Там что-то смертельно неправильно с явным и неявным привязкой PDO::PARAM_INT при повторном использовании подготовленного оператора ODBC.

CREATE TABLE mytab (
    col INT,
    something VARCHAR(20)
);

Работает: несколько строк

$pdoDB = new PDO('odbc:Driver=ODBC Driver 13 for SQL Server;
  Server='.DATABASE_SERVER.';
  Database='.DATABASE_NAME,
  DATABASE_USERNAME,
  DATABASE_PASSWORD
);
$pdoDB->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );

$values = ['here','are','some','values'];
$sql = "INSERT INTO mytab (something) VALUES (:something)";
$stmt = $pdoDB->prepare($sql);
foreach ($values as $value)
  $stmt->execute(['something'=>$value]);

Работы: одиночное целое

$values = [42];
$sql = "INSERT INTO mytab (col) VALUES (:col)";
$stmt = $pdoDB->prepare($sql);
foreach ($values as $value)
  $stmt->execute(['col'=>$value]);

Не работает: несколько целых чисел

$values = [1,3,5,7,11];
$sql = "INSERT INTO mytab (col) VALUES (:col)";
$stmt = $pdoDB->prepare($sql);
foreach ($values as $value)
  $stmt->execute(['col'=>$value]);

Он фактически успешно вставляет первую запись 1, но не работает, когда пытается повторить операцию при следующем выполнении.

PHP Неустранимая ошибка: Uncaught PDOException: SQLSTATE [22018]: Недопустимое значение символа для спецификации литья: 206 [Microsoft] [Драйвер ODBC 13 для SQL Server] [SQL Server] Столкновение типа операнда: текст несовместим с int (SQLExecute [ 206] в /build/php 7.0-lPMnpS/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:260)

Я подключаюсь из 64-разрядного Ubuntu 16.04, работающего под управлением PHP 7.0.8, используя Microsoft® ODBC Driver 13 (Preview) для SQL Server®


Я пробовал обернуть все это в PDO::beginTransaction и PDO::commit

Я также пробовал использовать PDOStatement::bindParam, но он выдает ту же самую ошибку.

Работы

$values = [1];
$sql = "INSERT INTO mytab (col) VALUES (:col)";
$stmt = $pdoDB->prepare($sql);
foreach ($values as $value){
  $stmt->bindParam('col', $value, PDO::PARAM_INT);
  $stmt->execute();
}

Не работает

$values = [1,2];
$sql = "INSERT INTO mytab (col) VALUES (:col)";
$stmt = $pdoDB->prepare($sql);
foreach ($values as $value){
  $stmt->bindParam('col', $value, PDO::PARAM_INT);
  $stmt->execute();
}

Мне кажется интересным отметить, что я получаю ту же ошибку, что и этот вопрос без ответа, используя PHP 5.6.9. Тем не менее, они не могут выполнить хотя бы один оператор, поэтому мне интересно, был ли частичный патч, учитывая, что точная строка, бросающая ошибку, переместилась из odbc_stmt.c:254 до odbc_stmt.c:260

Обход

Если я подготовлю оператор внутри цикла, то он работает нормально. Но я читал, что это очень неэффективно, и я должен иметь возможность повторно использовать инструкцию. Меня особенно беспокоит использование этого с массивными наборами данных. Это нормально? Есть ли что-то лучшее, что я могу сделать?

$values = [1,3,5,7,9,11];
$sql = "INSERT INTO mytab (col) VALUES (:col)";
foreach ($values as $value){
  $stmt = $pdoDB->prepare($sql);
  $stmt->execute(['col'=>$value]);
}

Ответ 1

В случае подготовленных операторов вы должны использовать bindParam вне цикла, обычно.

  1. bindParam - это один шаг
  2. установка связанных переменных - это повторяемый шаг (цикл)
  3. Вы должны запустить execute для каждого повторения

Я думаю, что-то подобное будет работать:

$stmt = $pdoDB->prepare("INSERT INTO mytab (col, key) VALUES (:col, :key)");

// bind params (by reference)
$stmt->bindParams(":col", $col, PDO::PARAM_STR); //bind variable $col
$stmt->bindParams(":key", $key, PDO::PARAM_INT); //bind variable $key

$values = ['here','are','some','values'];
foreach ($values as $i => $value) {
    $col = $value; //set col
    $key = $i; //set key
    $stmt->execute();
}