error_line() 返回 try 块内引发错误的相对行号,仅在 begin catch 块中有效;error_number() 返回整数错误号(如 8134),二者均须在 catch 内尽早调用,否则值丢失。

SQL Server 中必须用 ERROR_NUMBER() 和 ERROR_LINE() 获取错误号与行号
这两个函数只在 BEGIN CATCH 块内有效,且必须在任何可能中断执行的语句(比如 RETURN、新 BEGIN TRY 或再次出错)之前调用。一旦离开 CATCH 块,值就丢失了。
常见误区是把它们写在日志插入之后,或放在 IF @@TRANCOUNT > 0 ROLLBACK 后面——如果回滚失败(如事务已提交),后续语句可能不执行,导致错误信息没取到。
-
ERROR_NUMBER()返回整数错误号,比如2627(主键冲突)、547(外键约束违例)、8134(除零) -
ERROR_LINE()返回 TRY 块内的**相对行号**,不是整个存储过程的绝对行号;若 TRY 块从第 10 行开始,而错误发生在其中第 3 行,则返回3 - 不要用
@@ERROR替代:它只捕获上一条语句的错误号,且在IF判断后就被覆盖,不可靠
Oracle 中靠 SQLCODE 和 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() 定位真实行号
SQLCODE 是数字型错误码,但要注意它的符号含义:正数如 100 对应 NO_DATA_FOUND,负数才是标准 Oracle 错误(如 -2291 是外键违例)。直接用 SQLERRM 会带前缀(如 "ORA-01403: no data found"),想提取纯消息得传参:SQLERRM(-1403)。
最关键的是行号定位:SQLERRM 和 SQLCODE 只告诉你“在哪一个 EXCEPTION 块里被捕获”,而 DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() 才返回**实际出错的 PL/SQL 行号**(例如 ORA-06512: at "SCOTT.PROC_A", line 42)。
- 必须在
EXCEPTION块中立即调用,不能被其他语句隔开 - 它不显示调用链(比如谁调用了这个过程),只返回当前块内错误发生位置
- 若过程是动态执行(
EXECUTE IMMEDIATE),堆栈会断在动态语句那行,真实错误需查动态 SQL 内容
PostgreSQL 用 GET STACKED DIAGNOSTICS 提取错误上下文
PostgreSQL 不提供类似 ERROR_LINE() 的内置函数,但可在 EXCEPTION 块中用 GET STACKED DIAGNOSTICS 拿到更细粒度的信息,包括错误发生时的行号、列号、函数名等。
注意:它依赖于 PL/pgSQL 的诊断变量,必须先声明变量接收,再赋值。而且只有在异常真正抛出后(即进入 WHEN 分支时)才能获取。
- 常用字段:
pg_exception_context(上下文)、returned_sqlstate(SQLSTATE 码,如'23505'表示唯一冲突) - 行号字段是
pg_context的一部分,需解析字符串,不像 SQL Server 那样直接有ERROR_LINE() - 若在匿名 DO 块中出错,
pg_exception_context可能为空;建议在函数中使用以获得完整堆栈
别漏掉错误严重性判断和事务状态检查
光有错误号和行号不够。SQL Server 中 ERROR_SEVERITY() 小于 11 的错误(如 RAISERROR(..., 10, 1))根本进不了 CATCH;Oracle 中 SQLCODE = +1 是用户自定义异常,= 0 表示正常退出,这些都影响你是否该记录或重抛。
更隐蔽的坑是事务状态:ERROR_LINE() 告诉你哪行错了,但如果你在 TRY 里 BEGIN TRANSACTION 却忘了在 CATCH 里检查 @@TRANCOUNT 就直接 ROLLBACK,可能误滚外部已开启的事务,导致数据不一致。
- SQL Server:CATCH 中必须先
IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION,再记录日志 - Oracle:
SQLCODE为 0 时说明没异常,但若前面有COMMIT失败,仍可能留下未提交变更 - 所有数据库中,错误号和行号只是起点,下一步得结合对象权限、约束定义、绑定参数值一起看











