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

PHP使用sqlsrv调用MSSQL存储过程无法获取返回状态与结果报错排查

问题描述

我查阅过多个标题看起来与本问题一致的相关提问,但我的实际场景存在差异,尝试了所有可行方案仍无法得到预期结果,以下是我已尝试内容的简要说明:

我的MSSQL表结构

Use Testing
Go

If Exists (Select * From sys.objects Where object_id=OBJECT_ID('dbo.Test_Table') And type in ('U')) Drop Table dbo.Test_Table
Go

Create Table dbo.Test_Table(
    FirstName NVarchar(50) Not Null Default '',
    LastName NVarchar(50) Not Null Default '',
    Age Int Not Null Default 0,

    Constraint PK_Test_Table Primary Key Clustered (FirstName) With (Pad_Index=Off,Statistics_NoRecompute=Off,Ignore_Dup_Key=Off,Allow_Row_Locks=On,Allow_Page_Locks=On)
)

我的存储过程

Use Testing
Go

Set Ansi_Nulls On
Go
Set Quoted_Identifier On
Go

If Exists (Select * From sys.objects Where object_id=OBJECT_ID('dbo.SP_Test_Data') And type In ('P','PC')) Drop Procedure dbo.SP_Test_Data;
Go

Create Procedure dbo.SP_Test_Data
    @FirstName NVarchar(50) Out,@LastName NVarchar(50) Out,@Age Int Out
As
Begin
    Declare @status Int = 0;
    Begin Transaction
    Begin Try
        Insert Into Test_Table(FirstName,LastName,Age) Values (@FirstName,@LastName,@Age)
        If(@@Trancount > 0)
            Begin Commit Transaction;
            Set @status=1;
        End;
    End Try
    Begin Catch
        If @@Trancount > 0
            Begin RollBack Transaction;
            Set @status=0;
        End;
    End Catch
    Select Stat=@status,FirstName=@FirstName,LastName=@LastName,Age=@Age
    Return @status;
End;
Go

MSSQL Management Studio测试情况

Use Testing
Go

Declare @FirstName NVarchar(50) = 'John',@LastName NVarchar(50) = 'Doe',@Age Int = 43,@stat Int = 0;
Exec @stat = dbo.SP_Test_Data @FirstName Out,@LastName Out,@Age Out

该测试运行完全正常,插入成功时返回@stat=1,插入失败时返回@stat=0。

我的PHP代码

<?php

    $ServerName = '.\MSSQL2008';
    $DBaseName  = 'Testing';
    $Output = array();
    
    $firstName  = 'John';
    $lastName   = 'Doe';
    $age        = 43;
    
    $sp_params = array(
        array($firstName, SQLSRV_PARAM_INOUT),
        array($lastName, SQLSRV_PARAM_INOUT),
        array($age, SQLSRV_PARAM_INOUT)
    );
    
    try{
        $Scon = sqlsrv_connect($ServerName);
        $RQS = "Exec ".$DBaseName.".dbo.SP_Test_Data @firstName=?,@lastName=?,@age=?";
        $RST = sqlsrv_prepare($Scon, $RQS, $sp_params);
        if(!sqlsrv_execute($RST)){
            $Output = array('status'=>'failed','type'=>'sql error','debug'=>$RQS,'result'=>$RST);
        }
        else{
            if($row = sqlsrv_fetch_array($RST)){
                $Output = $row;
            }
        }
    }
    catch(Exception $e){$e->getMessage();}
    if(($errors = sqlsrv_errors())!= null){
        $Output = array('status'=>'failed','detail'=>$errors);
    }
    sqlsrv_close($ServerName);
    if(!empty($Output)){print_r($Output);}
?>

报错信息

无论存储过程执行成功还是失败,PHP侧都返回相同的报错:

Array ( [status] => failed [detail] => Array ( [0] => Array ( [0] => IMSSP [SQLSTATE] => IMSSP [1] => -28 [code] => -28 [2] => The active result for the query contains no fields. [message] => The active result for the query contains no fields. ) ) )

预期结果

希望能获取到存储过程的执行结果:执行成功返回1,失败返回0,同时希望能获取到如FirstName、Age等1-2个字段的值做校验。


解决方案

你的问题由多个错误点共同导致,逐个修复即可:

  1. 核心报错原因:存储过程中执行INSERT语句时,MSSQL默认会先返回一个仅包含受影响行数的结果集,这个结果集没有任何字段,你直接调用sqlsrv_fetch_array读取的就是这个空结果集,所以触发报错。
    • 最优修复方案:在存储过程的开头(Declare @status Int = 0;之前)添加SET NOCOUNT ON;,禁止存储过程返回DML操作的行计数结果,直接返回你最后SELECT的业务结果集。
    • 备选修复方案:如果不想修改存储过程,可以在PHP执行sqlsrv_execute之后,先调用sqlsrv_next_result($RST)跳到第二个业务结果集,再执行fetch操作。
  2. 参数绑定错误:SQLSRV驱动要求绑定IN/OUT类型的参数时,必须显式指定参数的长度和PHP类型,否则无法正确处理输出值,参数绑定代码修改为:
    $sp_params = array(
        array($firstName, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_UTF8), 50),
        array($lastName, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_STRING(SQLSRV_ENC_UTF8), 50),
        array($age, SQLSRV_PARAM_INOUT, SQLSRV_PHPTYPE_INT)
    );
    
  3. 数据库连接配置缺失:sqlsrv_connect仅传服务器名无法正常连接到指定数据库,需要补充连接配置:
    $connectionInfo = array(
        "Database" => $DBaseName,
        "UID" => "你的数据库登录账号",
        "PWD" => "你的数据库登录密码"
    );
    $Scon = sqlsrv_connect($ServerName, $connectionInfo);
    
    同时要增加连接失败的判断,避免后续操作调用空资源报错。
  4. 存储过程调用语句不规范:调用带OUTPUT参数的存储过程时,需要在参数后加OUTPUT标识,SQL语句修改为:
    $RQS = "Exec ".$DBaseName.".dbo.SP_Test_Data @firstName=? OUTPUT,@lastName=? OUTPUT,@age=? OUTPUT";
    
  5. 连接关闭参数错误:sqlsrv_close需要传入连接资源而非服务器名字符串,修改为:
    sqlsrv_close($Scon);
    

所有错误修复后即可正常获取存储过程返回的status及相关字段值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 02:57:04