必须用 exec @ret = proc_name @p1, @p2 output 捕获 return 值和 output 参数,二者均需显式绑定变量且 output 关键字不可省略;return 和 output 值仅在所有结果集完全读取或释放后才可用。

直接用 DECLARE + EXEC 捕获返回值和 OUTPUT 参数
SQL Server 存储过程的整数返回值(RETURN)和 OUTPUT 参数必须显式绑定到变量,否则取不到。不能靠 SELECT 或隐式赋值。
常见错误现象:执行完 EXEC proc_name @p1, @p2 OUTPUT 后直接查 @p2,结果是 NULL;或漏写 EXEC @ret = proc_name,导致 @ret 始终为 0。
-
RETURN值必须用EXEC @var = proc_name语法捕获,且该语句必须是整个批处理中调用存储过程的**唯一形式** -
OUTPUT参数变量需在EXEC前声明,并在调用时显式加OUTPUT关键字(大小写不敏感,但推荐大写) - 返回值和 OUTPUT 参数都只在存储过程完全执行完毕后才可用,中间不能穿插其他语句干扰上下文
示例:
DECLARE @ret INT, @o_id BIGINT; EXEC @ret = [nb_order_insert] @o_buyerid = 123, @o_id = @o_id OUTPUT; SELECT @ret AS [ReturnCode], @o_id AS [NewOrderId];
为什么 OUTPUT 参数必须带 OUTPUT 关键字
SQL Server 把参数分为输入、输出两类,仅靠声明时的 OUTPUT 标识不够——调用时也必须重申方向,否则引擎默认按输入参数处理,不会把值写回变量。
容易踩的坑:
- 写成
EXEC proc @p1, @p2(漏掉OUTPUT),@p2值不变,哪怕存储过程中已赋值 - 写成
EXEC proc @p1, @p2 OUTPUT但没在前面DECLARE @p2 ...,报错“必须声明标量变量” - 把
OUTPUT错写成OUT或out parameter,SQL Server 不识别
注意:OUTPUT 关键字只影响参数传递方向,不影响数据类型匹配。如果存储过程中定义为 @id INT OUTPUT,调用时变量也必须是 INT,否则可能截断或隐式转换失败。
多个 OUTPUT 参数和 RETURN 值能一起用吗
可以,且推荐一起用:用 RETURN 表达执行状态(如 0=成功,1=主键冲突,2=权限不足),用 OUTPUT 返回业务数据(如新生成 ID、计数、汇总值)。
但要注意顺序和兼容性:
-
EXEC @ret = proc @p1, @p2 OUTPUT, @p3 OUTPUT是合法的,所有OUTPUT参数必须列在调用语句中并加关键字 - 不能跳过中间参数只传第 1 和第 3 个,除非存储过程本身支持默认值且你用命名参数方式(
@p1 = val, @p3 = val) - 如果存储过程里用了
SET NOCOUNT ON,它只抑制“X 行受影响”消息,不影响RETURN和OUTPUT的获取
性能上无额外开销,这两类返回机制都走同一通信通道,只是协议层面的标记不同。
从应用程序调用时,OUTPUT 参数和 RETURN 值的获取时机很关键
无论用 ADO.NET、JDBC 还是 ODBC,RETURN 和 OUTPUT 参数的值**只有在所有结果集被完全读取或释放后才就绪**。这是 SQL Server 协议设计决定的——它们打包在 RPC 响应的最后一个数据包里。
典型错误场景:
- 执行一个返回结果集 +
OUTPUT的存储过程,应用端只读了前几行就关掉DataReader,后续再取OUTPUT值,得到的是初始值(如 0 或NULL) - 用 Entity Framework 调用带
OUTPUT的存储过程,没调用SqlDataReader.NextResult()到末尾,SqlParameter.Value仍为空 - JDBC 中没调用
execute()后的getMoreResults()直到返回false,registerOutParameter注册的值拿不到
最稳妥的做法:先遍历完所有结果集(哪怕丢弃),再读 RETURN 和 OUTPUT。这点比纯 T-SQL 批处理更易出错,因为逻辑分散在不同层。










