PHP sqlsrv PDOStatement::rowCount返回-1但fetch可正常获取结果问题
问题原因
PDO_SQLSRV驱动对rowCount()方法的返回逻辑有特殊规则:
- 默认情况下,
rowCount()仅返回INSERT/UPDATE/DELETE这类写操作的影响行数,SELECT查询不会修改数据,默认返回-1 - 即使开启了滚动游标
PDO::CURSOR_SCROLL,如果SQL语句包含多段执行逻辑(比如你代码里先DECLARE定义变量、SET赋值,再执行SELECT),驱动会被前面非查询语句的执行计数干扰,无法正确识别最终SELECT返回的行数,就会返回-1
可落地的解决方案
你可以任选以下任意一种方案解决问题:
- 方案1(最稳妥,全驱动兼容):放弃用
rowCount()统计SELECT结果行数,改用fetchAll()获取全部结果后用count()统计$queryLoc->execute(); // 先拿到所有查询结果 $resultList = $queryLoc->fetchAll(PDO::FETCH_ASSOC); // 直接统计数组长度得到行数 $numero = count($resultList); echo $numero; echo "<h1>MEDIA INCASSI DAL ".date('d-m-Y',strtotime($dataInizio))." AL ".date('d-m-Y',strtotime($dataFine))."</h1>"; $id=0; // 遍历数组即可,不用再fetch foreach($resultList as $resultLoc){ // 原有业务逻辑不变 } - 方案2(优化写法同时解决问题):删除SQL内的变量声明逻辑,改用PDO参数绑定传参,单条SELECT语句下滚动游标可正常统计行数,同时还能解决原代码的SQL注入风险
// 去掉DECLARE/SET部分,直接用占位符传参 $sqlLoc= " SELECT noteincassi.CodLocale,Insegna,Citta FROM [Edera].[dbo].[NoteIncassi] JOIN edera.dbo.AnagraficaLocali ON AnagraficaLocali.CodLocale=NoteIncassi.CodLocale WHERE DataIncasso >= ? AND DataIncasso <= ? AND tipoincasso = '6' AND sospeso = 0 GROUP BY noteincassi.CodLocale,insegna,Citta ORDER BY Insegna "; $queryLoc = $conn->prepare($sqlLoc,array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); // 绑定参数执行 $queryLoc->execute([$dataInizio, $dataFine]); // 此时rowCount()可返回正确行数 echo $numero=$queryLoc->rowCount(); - 方案3(最小改动适配原有SQL):在SQL开头加
SET NOCOUNT ON;,屏蔽前面非查询语句的计数干扰,驱动可正常获取最终SELECT的行数$sqlLoc= " -- 新增这一行即可 SET NOCOUNT ON; DECLARE @Data2 AS DATE; SET @Data2 = CONVERT(DATE,CONVERT(date, '$dataFine'), 102); DECLARE @Data1 AS DATE; SET @Data1 = CONVERT(DATE,CONVERT(date, '$dataInizio'), 102); SELECT noteincassi.CodLocale,Insegna,Citta FROM [Edera].[dbo].[NoteIncassi] JOIN edera.dbo.AnagraficaLocali ON AnagraficaLocali.CodLocale=NoteIncassi.CodLocale WHERE DataIncasso >= @Data1 AND DataIncasso <= @Data2 AND tipoincasso = '6' AND sospeso = 0 GROUP BY noteincassi.CodLocale,insegna,Citta ORDER BY Insegna ";
内容的提问来源于stack exchange,提问作者Alessandro
相关产品推荐
相关产品推荐

