Préparé déclaration ne peut pas être exécutée plusieurs fois avec des valeurs entières

Comment puis-je correctement ré-exécuter une instruction préparée en utilisant des valeurs entières différentes?

Il y a quelque chose reliques de mal avec explicites et implicites de liaison PDO::PARAM_INT lors de la réutilisation d'un ODBC déclaration préparée.

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

Fonctionne : plusieurs chaînes de caractères

$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]);

Fonctionne : un simple entier

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

ne fonctionne pas: nombres entiers multiples

$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]);

il insère effectivement avec succès le premier enregistrement 1 mais échoue quand il tente de réutiliser l'instruction sur l'exécution suivante.

PHP Fatal error: Uncaught PDOException: SQLSTATE[22018]: invalides character value for cast specification: 206 [Microsoft] [ODBC Driver 13 for SQL Server] [SQL Server] Operand type clash: text is incompatible with int (SQLExecute[206] at /build/php7.0-lPMnpS / php7.0-7.0.8 / ext/pdo_odbc / odbc_stmt.C: 260)

je me connecte à partir de 64 bits Ubuntu 16.04 lancer PHP 7.0.8 en utilisant le pilote Microsoft® ODBC 13 (Preview) pour SQL Server®


j'ai essayé d'envelopper le tout dans PDO::beginTransaction et PDO::commit

j'ai aussi essayé d'utiliser PDOStatement::bindParam mais il jette l'exacte même erreur.

Œuvres

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

Ne Fonctionne Pas

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

je pense qu'il est intéressant de noter que j'obtiens exactement la même erreur que cette question sans réponse en utilisant PHP 5.6.9. Cependant, ils ne sont pas capables d'exécuter même une déclaration, donc je me demande s'il y a eu un patch partiel considérant la ligne exacte jetant l'erreur a déménagé de odbc_stmt.c:254 à odbc_stmt.c:260

solution de contournement

si je prépare la déclaration à l'intérieur de la boucle, puis il fonctionne très bien. mais j'ai lu que c'est très inefficace et je devrais pouvoir réutiliser la déclaration. Je suis particulièrement inquiet de l'utiliser avec des ensembles de données massives. Est-ce OK? Est-il quelque chose de mieux que je peux faire?

$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]);
}
5
demandé sur Community 2016-08-22 23:26:55

1 réponses

dans le cas de déclarations préparées vous devez utiliser bindParam en dehors de la boucle, habituellement.

  1. bindParam est un pas simple
  2. jeu de lier des variables est un reproductibles à l'étape (boucle)
  3. vous devez exécuter execute pour chaque répétition

je suppose, quelque chose comme ça marcherait:

$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();
}
0
répondu seboettg 2018-08-09 13:22:35