我正在使用通过ODBC连接的MSSQL数据库。
在具有嵌套SELECT语句的查询上使用PDO::bindValue()
时,它无法绑定嵌套SELECT中的值(主SELECT上没有问题)。
这是一段失败的示例代码:
$stmt = $cmdb->prepare("SELECT ci.CI FROM dbo.cmdb_ci AS ci " .
"INNER JOIN dbo.cmdb_model AS m ON m.ModelID = ci.Modelid " .
"INNER JOIN dbo.cmdb_class AS c ON c.ClassID = m.Classid " .
"WHERE (c.ClassID = :classid) " .
"AND (ci.CI IN (SELECT ci2.CI " .
"FROM dbo.cmdb_ci AS ci2 " .
"INNER JOIN dbo.cmdb_ci_status AS st2 ON st2.CI = ci2.CI " .
"WHERE st2.LocationID = :locationid))");
$stmt->bindValue("classid", 13);
$stmt->bindValue("locationid", 1011);
$stmt->execute();
if ($rows = $stmt->fetchAll())
$stmt->closeCursor();
foreach ($rows as $row)
echo $row["CI"];
我得到的错误是:
SQLSTATE [22018]:强制转换规范的字符值无效:206 [Microsoft] [SQL Server Native Client 11.0] [SQL Server]操作数类型冲突:text与int不兼容(/ builddir / build /中的SQLExecute [206] BUILD / PHP-5.4.16 / EXT / PDO_ODBC / odbc_stmt.c:254)
如果我遗漏bindValue()
for“:locationid”并直接在查询中插入“1011”,则调用完成且没有错误并且结果正确。
这是PDO中的错误,还是我必须以不同方式调用bindValue()?
答案 0 :(得分:5)
As(我从评论中读到)告诉bindValue
传递的值是一个整数没有解决问题......
$stmt->bindValue( "locationid", 1011, PDO::PARAM_INT );
...我认为由于某种原因(a bug in pdo_odbc ?),无论您在bindValue
上指定为第三个参数,参数都会以字符串形式输入查询。
然后我建议通过将值>>整合到查询中来解决这个问题。
在最后一行:
"WHERE st2.LocationID = CAST( :locationid, int ) ))"
这不是很优雅但可能适用于找到pdo_odbc的修补程序/补丁
即使这不起作用,也会有一个更优雅的解决方案(当然是临时修复)。
您写道:
如果我遗漏了#34;的bindValue():locationid"并插入' 1011'直接进入查询,调用完成没有错误并且结果正确。
因此,您可以直接将位置ID 放入查询中。
假设位置ID 存储在$locationId
中,则查询的最后一行变为:
"WHERE st2.LocationID = $locationId))");
由于这很容易导致sql-injection $locationId
必须事先进行清理(或验证)。
该值必须是一个正整数,所以我建议使用更简单,更安全的方法,而不是转义它:检查$locationId
只是数字...
if( ! ctype_digit( (string) $locationId ) ) {
// location id is invalid
// do not proceed !
}
答案 1 :(得分:1)
可能是位置ID实际上是作为字符串存储在MSSQL中而不是int吗?添加引号时是否有效? $ stmt-> bindValue(“locationid”,“1011”,PDO :: PARAM_STR);