准备好的语句不能用整数值多次执行
Posted
技术标签:
【中文标题】准备好的语句不能用整数值多次执行【英文标题】:Prepared statement cannot be executed multiple times with integer values 【发布时间】:2016-12-29 12:20:03 【问题描述】:如何使用不同的整数值正确地重新执行准备好的语句?
在重用 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][SQL Server 的 ODBC 驱动程序 13][SQL Server]操作数类型冲突:文本与 int 不兼容(SQLExecute[ 206] 在/build/php7.0-lPMnpS/php7.0-7.0.8/ext/pdo_odbc/odbc_stmt.c:260)
我使用Microsoft® ODBC Driver 13 (Preview) for SQL Server®从运行 PHP 7.0.8 的 64 位 Ubuntu 16.04 连接
我已经尝试用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 时遇到了与 unanswered question 完全相同的错误。但是,他们甚至无法执行一条语句,所以我想知道是否存在部分补丁,考虑到引发错误的确切行已从 odbc_stmt.c:254
移动到 odbc_stmt.c:260
解决方法
如果我在循环中准备语句inside,那么它工作得很好。但我读到这是非常低效的,我应该能够重用陈述。我特别担心将它与大量数据集一起使用。这个可以吗?有没有更好的办法?
$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]);
【问题讨论】:
不知道是否有帮助,但line 260 是在以前版本的 PHP 中引发错误的同一行代码 如果表只有一个 int 列是否有效? @DavidG 不,我也明确测试过。 如果你在循环外绑定到某个var,然后在循环内只更新那个var的值并只调用execute,它是否有效? 如果你使用$stmt->execute(['col'=>intval($value]));
,它是否有效?
【参考方案1】:
对于准备好的语句,您通常必须在循环外使用bindParam
。
bindParam
一步到位
设置绑定变量是一个可重复的步骤(循环)
你必须为每次重复运行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();
【讨论】:
以上是关于准备好的语句不能用整数值多次执行的主要内容,如果未能解决你的问题,请参考以下文章
PHP password_verify 不能与准备好的语句一起使用