【问题标题】:PHP PDO Query returning an empty array when using bindParam使用 bindParam 时 PHP PDO 查询返回一个空数组
【发布时间】:2014-10-14 00:02:26
【问题描述】:

有点被这个难住了。我已经开发了大约一个星期,也许两个,所以这可能是一个菜鸟的错误,但这是我所拥有的:

<?php

$msDB = new PDO('odbc:Driver={SQL Server Native Client 11.0};Server=SOMESERVER;Trusted_Connection=yes;');
try{

//set values for query
$s="4";
$d1="'2014-10-01 00:00:00'";
$d2="'2014-10-31 23:59:59'";

//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN 
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID) 
AND (t1.SELECTION = :s) 
AND (tN.RESPONSE_DATE BETWEEN :d1 AND :d2))";

//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->bindParam(':s',$s, PDO::PARAM_INT);
$tbe->bindParam(':d1',$d1, PDO::PARAM_STR);
$tbe->bindParam(':d2',$d2, PDO::PARAM_STR);

//execute query
$tbe->execute();

//fetch resulting data
$res = $tbe->fetchAll(PDO::FETCH_ASSOC);}

//error handling
catch (PDOException $e) {
    throw new pdoDbException($e);
}
//print the resulting array
print_r($res);

//set initial count
$cnt=0;

//loop through and increment count
foreach($res as $key=>$value){
    foreach($value as $v2 ){
        $cnt++;
    }
}

//return count value
echo "Total:<br/>".$cnt."<br/>";

?>

我希望这会返回数字 3 的结果集。当我手动指定查询中的值时,一切都按预期工作并返回数字 3。

但是,如果我使用 bindParam 方法,它不会返回任何内容,也不会引发任何类型的错误。它只是返回一个空数组。

我还可以分解 $q1 中的查询集并将值连接到其中,它也可以完美地工作。我之前并没有真正使用过 bindParam,但据我所知,我使用它是正确的。

作品:

//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
AND (t1.SELECTION = ".$s.")
AND (tN.RESPONSE_DATE BETWEEN ".$d1." AND ".$d2."))";

当我在 MSSQL Server Management Studio 中运行查询时,它也会返回我期望的结果集。

谁能告诉我我做错了什么?

【问题讨论】:

  • 也许这个link 会帮助你
  • @khrisna-gunanasurya 谢谢。在阅读了该帖子并进行了一些广泛的测试之后,似乎 ODBC 驱动程序正在将日期格式字符串转换为 MSSQL 服务器不期望的内容。使用变量而不是绑定参数似乎是唯一可行的解​​决方案。再次感谢。

标签: php sql-server pdo


【解决方案1】:

PDO::bindParam 和 PDO::bindValue 传递的默认数据类型是ALWAYS文本。从 MSSQL 中的数据类型文本转换只能转换为 CHAR、VARCHAR、NCHAR 和 NVARCHAR。由于数据类型问题,必须将值从文本转换为 CHAR 或 VARCHAR,然后从那里转换为 DATETIME。然而,这是一种隐式转换,根据传递给查询的值,可能会导致舍入错误、截断或只是转换失败。

这个,工作:

//create query variable
$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
(SELECT * FROM SURVEY_RESPONSE AS tN 
WHERE (tN.ID = t1.SURVEY_RESPONSE_ID) 
AND (tN.RESPONSE_DATE BETWEEN :d1 AND :d2))";

//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->bindParam(':d1',$d1, PDO::PARAM_INT);
$tbe->bindParam(':d2',$d2, PDO::PARAM_INT);

确实有效:

$q1 = 'SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
    (SELECT * FROM SURVEY_RESPONSE AS tN
    WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
    AND (tN.RESPONSE_DATE BETWEEN CONVERT(datetime,CONVERT(VARCHAR(MAX),?)) 
    AND CONVERT(datetime,CONVERT(VARCHAR(MAX),?))))';

//run prepare and bindParam
$tbe = $msDB->prepare($q1);
$tbe->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$tbe->bindParam(1,$d1);
$tbe->bindParam(2,$d2);

即使我将绑定参数转换为 INT 类型,它们仍然作为导致失败的文本传递给 MSSQL。

不过,我的建议是简单地使用原始的解决方法,即直接像这样直接传入变量,并将变量作为双引号字符串:

$q1 = "SELECT ID FROM SURVEY_QUESTION_RESPONSE AS t1 WHERE EXISTS
    (SELECT * FROM SURVEY_RESPONSE AS tN
    WHERE (tN.ID = t1.SURVEY_RESPONSE_ID)
    AND (t1.SELECTION = '$s')
    AND (tN.RESPONSE_DATE BETWEEN '$date1' AND '$date2'))";

引用的字符串更容易处理,而且更不容易出错,因为它根本不需要转换,直接传递给 MSSQL Server 没有问题。

由于 MSSQL Server 的额外处理,我注意到转换的性能略有下降。执行转换的查询比没有执行的查询多花了大约半秒时间。

感谢 @meda 帮助解决问题!

【讨论】:

  • 有趣的问答++
【解决方案2】:

我今天收到了这个错误,我花了很多时间。 将 PHP 版本升级到 PHP7 后,使用 sqlsrv:database 驱动程序而不是 dblib:dbname 会出现此问题。 为了避免这种情况,仍然使用 dblib:dbname 事件 PHP7 FPM 已经支持 sqlsrv:database 驱动程序。

【讨论】:

    猜你喜欢
    • 2012-05-03
    • 2011-12-27
    • 1970-01-01
    • 2015-05-31
    • 2013-04-21
    • 2012-11-28
    • 2017-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多