如何在SQLcl批量加载多表时遇到错误立即终止执行
如何在SQLcl批量加载多表时遇到错误立即终止执行
我之前也踩过这个坑!你遇到的问题本质是SQLcl的load命令是客户端工具命令,不是标准SQL语句,所以你原来加的WHENEVER SQLERROR根本抓不到它的执行错误——这就是为什么tableB加载失败后,脚本还会自顾自跑tableC的原因。
核心解决思路就是:每个load命令执行后,手动检查SQLcl内置的错误状态变量,一旦发现非0错误码就立刻终止脚本。我给你整理了两种场景的解决方案,按需选用:
场景1:允许已成功加载的表保留,失败即终止后续操作
这种是贴合你最初需求的方案:前面的表加载成功就保留,只要某一步失败,立刻停下不加载后面的表。
修改后的完整脚本如下:
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK WHENEVER OSERROR EXIT SQL.SQLCODE ROLLBACK -- 基础配置:不允许加载错误,加载前清空目标表 SET LOAD ERRORS 0 SET LOAD TRUNCATE ON -- 加载tableA并检查错误 LOAD tableA input_tableA.csv -- 把SQLcl内置的最后错误码赋值给自定义变量 VAR err_code NUMBER BEGIN :err_code := SQL.LAST_ERROR_CODE; END; / -- 错误检查:非0则终止脚本 IF :err_code != 0 THEN PROMPT 【错误】tableA加载失败,立即终止后续操作 EXIT :err_code ROLLBACK END IF -- 加载tableB并检查错误 LOAD tableB input_tableB.csv BEGIN :err_code := SQL.LAST_ERROR_CODE; END; / IF :err_code != 0 THEN PROMPT 【错误】tableB加载失败,立即终止后续操作 EXIT :err_code ROLLBACK END IF -- 加载tableC并检查错误 LOAD tableC input_tableC.csv BEGIN :err_code := SQL.LAST_ERROR_CODE; END; / IF :err_code != 0 THEN PROMPT 【错误】tableC加载失败,立即终止后续操作 EXIT :err_code ROLLBACK END IF PROMPT 所有表加载完成,全部成功!
关键细节说明:
SQL.LAST_ERROR_CODE是SQLcl内置的绑定变量,专门记录最后一次客户端命令(比如load)的执行结果,0代表成功,非0代表失败。- 用PL/SQL块把这个内置错误码转存到自定义变量
err_code里,再用SQLcl的客户端IF语句做判断,失败就用EXIT直接终止整个脚本。 - 加
PROMPT语句是为了在控制台输出明确的错误提示,避免你在几百个表的加载日志里漏看失败信息。
场景2:全量原子性加载(要么全成功,要么全回滚)
如果你的表之间有外键关联,或者要求数据的一致性,希望任何一个表加载失败,所有已加载的内容都回滚,那就要加上关闭自动提交的配置,脚本修改如下:
WHENEVER SQLERROR EXIT SQL.SQLCODE ROLLBACK WHENEVER OSERROR EXIT SQL.SQLCODE ROLLBACK -- 基础配置:不允许错误,清空目标表,关闭自动提交 SET LOAD ERRORS 0 SET LOAD TRUNCATE ON SET LOAD AUTOCOMMIT OFF -- 关键:关闭load命令的自动提交,统一控制事务 -- 加载tableA并检查 LOAD tableA input_tableA.csv VAR err_code NUMBER BEGIN :err_code := SQL.LAST_ERROR_CODE; END; / IF :err_code != 0 THEN PROMPT 【错误】tableA加载失败,回滚所有操作并终止 ROLLBACK; EXIT :err_code END IF -- 加载tableB并检查 LOAD tableB input_tableB.csv BEGIN :err_code := SQL.LAST_ERROR_CODE; END; / IF :err_code != 0 THEN PROMPT 【错误】tableB加载失败,回滚所有操作并终止 ROLLBACK; EXIT :err_code END IF -- 加载tableC并检查 LOAD tableC input_tableC.csv BEGIN :err_code := SQL.LAST_ERROR_CODE; END; / IF :err_code != 0 THEN PROMPT 【错误】tableC加载失败,回滚所有操作并终止 ROLLBACK; EXIT :err_code END IF -- 所有表加载成功,统一提交事务 COMMIT; PROMPT 所有表加载完成,全部成功,事务已提交!
关键细节说明:
SET LOAD AUTOCOMMIT OFF会让load命令执行后不自动提交数据,所有加载的内容都在同一个事务里。- 任何一步失败时,执行
ROLLBACK会把之前所有加载的内容全部撤销,避免数据库出现部分加载的不一致状态。 - 只有所有步骤都成功,才会执行
COMMIT把所有数据持久化到数据库。
额外小提示
如果要加载几百个表,重复写加载+检查的代码太麻烦,可以把单表加载逻辑封装成一个脚本片段,比如写一个load_single_table.sql,然后主脚本里循环调用它,能省不少事。
备注:内容来源于stack exchange,提问作者Eduard Uta
相关产品推荐
相关产品推荐

