预准备语句不能使用整数值多次执行

Prepared statement cannot be executed multiple times with integer values

提问人:Jeff Puckett 提问时间:8/23/2016 最后编辑:CommunityJeff Puckett 更新时间:2/5/2019 访问量:1334

问:

如何使用不同的整数值正确地重新执行准备好的语句?

在重用 ODBC 准备语句时,显式和隐式绑定存在致命错误。PDO::PARAM_INT

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 致命错误:未捕获的 PDOException:SQLSTATE[22018]:强制转换规范的字符值无效:206 [Microsoft][ODBC Driver 13 for SQL Server][SQL Server]操作数类型冲突:文本与 int 不兼容(SQLExecute[206] 位于 /build/php7.0-lPMnpS/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:260)

我正在使用适用于 SQL Server® 的 Microsoft® ODBC Driver 13(预览版)从运行 PHP 7.0.8 的 64 位 Ubuntu 16.04 进行连接


我试过将整个事情包装在 PDO::beginTransactionPDO::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]);
}
php sql-server pdo odbc 准备语句

评论

1赞 DavidG 8/23/2016
不知道它是否有帮助,但第 260 行与在以前版本的 PHP 中抛出错误的代码行相同
0赞 DavidG 8/23/2016
如果表只有一个 int 列,它是否有效?
0赞 Jeff Puckett 8/23/2016
@DavidG不,我也明确测试过了。
0赞 erg 8/24/2016
如果您在循环外部绑定到某个 var,然后在循环内仅更新该 var 的值并仅调用 execute,它是否有效?
0赞 drews 5/16/2018
如果你使用,它有效吗?$stmt->execute(['col'=>intval($value]));

答:

-1赞 seboettg 8/9/2018 #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();
}