You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP PDO调用SQL Server存储过程:为何需2次nextRowset()?行集含什么?

问题描述

我正在用PHP PDO向SQL Server存储过程插入数据,需要获取受影响行数、返回值和输出参数,目前代码能正常运行。

连接代码:

$conn = new PDO("sqlsrv:Server=$hostname;Database=$dbname", "$username", "$pw");
echo "Connection established.<br />";
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);;
$conn->setAttribute(PDO::SQLSRV_ATTR_ENCODING, PDO::SQLSRV_ENCODING_SYSTEM);

调用存储过程的代码:

$sql = "EXEC ? = the_stored_procedure ?, ?";
$sth = $conn->prepare($sql);
$retval = 99;
$bite = '999';

$sth->bindParam(1, $retval, PDO::PARAM_INT | PDO::PARAM_INPUT_OUTPUT, PDO::SQLSRV_PARAM_OUT_DEFAULT_SIZE);
$sth->bindParam(2, $bite);
$sth->bindParam(3, $responseMessage, PDO::PARAM_STR | PDO::PARAM_INPUT_OUTPUT, 512);
$sth->execute();

获取结果的代码:

echo "rowcount: " . $sth->rowCount() . "<br>";
$sth->nextRowset();
$sth->nextRowset();
echo "RETURN: " . $retval . "<br>";
echo "OUTPUT: " . $responseMessage . "<br>";

我的问题是:为什么需要调用2次nextRowset()?这两个行集中包含什么内容?

另外,如果我把EXEC语句改成:

$sql = "SET NOCOUNT ON; EXEC ? = ComC_i_Survey_Start_php ?, ?";

就无法获取行计数,但不用调用nextRowset()就能直接拿到返回值和输出参数:

echo "<br>RETURN:" . $retval . "<br>";
echo "<br>OUTPUT:" . $responseMessage . "<br>";

回答

为什么需要两次nextRowset()?

这是SQL Server和PDO SQLSRV驱动的特性决定的:当你不添加SET NOCOUNT ON时,执行带返回值的存储过程会生成两个额外的行集,必须遍历完这些行集,PDO才能将存储过程的返回值和输出参数填充到你绑定的变量中。

两个行集的具体内容:

  1. 第一个行集:存储过程中DML操作(比如你代码里的INSERT)产生的受影响行数消息。SQL Server默认会为每个DML操作返回这个结果集,这也是你能通过$sth->rowCount()拿到行数的原因。
  2. 第二个行集:存储过程的返回值结果集。因为你用了EXEC ? = the_stored_procedure的语法来捕获存储过程的返回值,SQL Server会把这个返回值包装成一个单独的行集返回。

只有调用两次nextRowset()跳过这两个行集后,PDO才会同步更新你绑定的$retval(返回值)和$responseMessage(输出参数)变量的值。

关于SET NOCOUNT ON的情况

SET NOCOUNT ON会抑制SQL Server返回DML操作的受影响行数消息,也就是去掉了第一个行集。此时执行存储过程不会生成额外的行集(如果存储过程内部没有SELECT语句的话),所以PDO不需要遍历行集就能直接访问绑定的输出参数——但代价是你再也无法通过rowCount()获取受影响的行数了,因为这个信息被强制抑制。


内容的提问来源于stack exchange,提问作者user9124752

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 18:20:36