有点被这个难倒。我已经开发了大约一个星期了,可能是两个,所以它可能是一个noob错误,但这就是我所拥有的:
<?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中运行查询时,它还会返回我期望的结果集。
谁能告诉我我做错了什么?
答案 0 :(得分:1)
PDO :: bindParam和PDO :: bindValue传递的默认数据类型是始终文本。从MSSQL中的数据类型文本转换只能对CHAR,VARCHAR,NCHAR和NVARCHAR进行转换。由于数据类型问题,必须将值从文本转换为CHAR或VARCHAR,然后从那里转换为DATETIME。但这是一个隐式转换,根据传递给查询的值,可能会导致舍入错误,截断或转换失败。
这是 NOT 工作:
//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帮助解决问题!
答案 1 :(得分:0)
我今天得到了这个错误并花了很多时间。 将PHP版本升级到PHP7后,使用sqlsrv:database驱动程序而不是dblib:dbname会出现此问题。 为了避免这种情况,仍然使用 dblib:dbname 事件PHP7 FPM已经支持sqlsrv:数据库驱动程序。