PDO :: bindValue()在嵌套SELECT

时间:2017-04-04 12:19:26

标签: php pdo

我正在使用通过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()?

2 个答案:

答案 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);