sql server用@@rowcount、mysql用row_count()、postgresql用get diagnostics获取影响行数,均需在目标语句后立即执行,且各数据库对无匹配更新的返回值均为0,但细节行为存在差异。

SQL Server 中用 @@ROWCOUNT 捕获存储过程内最后一条语句影响行数
在 SQL Server 存储过程中,@@ROWCOUNT 是最常用、最直接的方式获取刚执行的 INSERT/UPDATE/DELETE 影响行数。但它极易被后续语句覆盖——哪怕是一条 SELECT 或 IF 判断都会重置它。
实操建议:
- 必须在目标语句(如
UPDATE)后「立即」读取@@ROWCOUNT,中间不能夹任何其他 SQL 语句 - 推荐立刻存入局部变量:
DECLARE @rows INT = @@ROWCOUNT; - 若存储过程含多个 DML 操作,且需分别记录,每条后都要单独捕获,不能只查一次
-
SET NOCOUNT ON不影响@@ROWCOUNT,但能避免客户端收到“X 行受影响”消息,提升网络效率
MySQL 存储过程中用 ROW_COUNT() 获取上一条语句影响行数
MySQL 用函数 ROW_COUNT() 替代 @@ROWCOUNT,行为类似但有关键区别:对 SELECT 返回 -1,对无匹配的 UPDATE 或 DELETE 返回 0,这点和 SQL Server 不同。
常见陷阱:
-
ROW_COUNT()在存储过程里调用时,必须紧接在目标语句之后;函数本身不带参数,写成ROW_COUNT(),不是ROW_COUNT(少括号会报错) - 如果语句是
INSERT ... ON DUPLICATE KEY UPDATE,返回值可能为1(插入)、2(更新)、0(无变更),需结合业务逻辑判断 - 在触发器中调用
ROW_COUNT()会返回触发该触发器的原始语句影响行数,不是触发器内语句的
从应用层调用时如何拿到影响行数(以 C# SqlCommand 为例)
存储过程内部的 @@ROWCOUNT 或 ROW_COUNT() 只作用于数据库端,应用层想拿到这个值,必须显式返回——不能依赖 ExecuteNonQuery() 的返回值,因为该方法默认只返回存储过程最后一个语句的影响行数,且前提是存储过程没用 SET NOCOUNT ON。
稳妥做法:
- 在存储过程末尾加
SELECT @@ROWCOUNT(SQL Server)或SELECT ROW_COUNT()(MySQL),然后用ExecuteScalar()获取 - 更规范的方式是用
OUTPUT参数:SQL Server 存储过程中定义@AffectedRows INT OUTPUT,赋值后由调用方接收 - 避免依赖
ExecuteNonQuery()的返回值——一旦存储过程里有SET NOCOUNT ON,它就永远返回-1
PostgreSQL 存储过程(PL/pgSQL)没有内置行数变量,得靠 GET DIAGNOSTICS
PostgreSQL 的函数/过程不提供类似 @@ROWCOUNT 的全局变量,必须用 GET DIAGNOSTICS 显式提取。它只能在 PERFORM 或 DML 语句后的 EXCEPTION 块或普通块中使用,且仅对当前事务中最近一次执行的语句有效。
典型写法:
PERFORM UPDATE users SET name = 'x' WHERE id = 1; GET DIAGNOSTICS affected_rows = ROW_COUNT;
注意点:
-
GET DIAGNOSTICS必须紧跟在目标语句之后,中间不能有其他 PL/pgSQL 语句(包括RAISE) - 变量
affected_rows需提前声明为INTEGER - 对
INSERT ... RETURNING等带返回值的语句,ROW_COUNT返回的是实际插入/更新/删除的行数,不是RETURNING返回的行数
真正容易被忽略的是:不同数据库对“无匹配更新”的定义不一致——SQL Server 的 UPDATE 若没命中任何行,@@ROWCOUNT 是 0;MySQL 的 ROW_COUNT() 同样返回 0;但 PostgreSQL 的 ROW_COUNT 在这种情况下也返回 0,可一旦中间有 RETURNING 或游标操作,逻辑就容易串。别假设它和你上次用的数据库一样。











