Perl DBI操作DB2时临时表跨do()失效导致MERGE后目标表为空问题
问题根因
目标表无数据和do()方法本身是否保留临时表无关,是两个问题共同导致的:
- DB2全局临时表默认配置为
ON COMMIT DELETE ROWS:即事务提交时自动清空表内所有数据。而Perl DBI对接DB2时默认开启AutoCommit自动提交开关,意味着每一次$DbHandle->do()调用执行完单条SQL后,会立刻触发一次事务提交。执行INSERT往临时表写数据的do调用完成后就触发了提交,临时表数据被全部清空,等后续执行MERGE语句时,临时表已经是空表,自然不会对目标表产生任何写入/更新操作。 - MERGE语句存在语法错误:原代码中
WHEN MATCHED ) THEN片段多了一个多余的右括号,SQL执行时会直接抛出语法错误,若错误捕获逻辑未正常触发,也会导致逻辑不生效。
修复方案
不需要把多条SQL拼到同一个do()调用里执行,按以下步骤调整即可:
- 两种方式选其一解决临时表数据被清空的问题:要么初始化DBI连接时关闭
AutoCommit,所有SQL执行完成确认无错后再手动提交,异常时回滚;要么声明临时表时追加ON COMMIT PRESERVE ROWS参数,让临时表在提交后保留数据,兼容AutoCommit开启场景。 - 声明临时表时建议追加
WITH REPLACE参数,避免同会话下已有同名临时表导致建表报错。 - 删除MERGE语句中
WHEN MATCHED后多余的右括号,修正语法错误。
修正后的可运行代码
sub MergePolygonNameTable() { my $table = "THESCHEMA.NAME"; print "Merging into ${table} table. ", scalar localtime, "\n"; eval { # 建表时加WITH REPLACE避免同名临时表冲突,加ON COMMIT PRESERVE ROWS保证提交后数据不丢失 $DbHandle->do(" declare global temporary table session.TEMP_NAME (POLICY_MASTER_ID INT ) WITH REPLACE ON COMMIT PRESERVE ROWS ; "); $DbHandle->do(" CREATE UNIQUE INDEX session.TEMP_NAME_IDX1 ON session.TEMP_NAME (POLICY_MASTER_ID ASC )"); $DbHandle->do(" insert into session.TEMP_NAME (POLICY_MASTER_ID ) SELECT pm.ID as POLICY_MASTER_ID FROM THESCHEMA.POLICY_MASTER pm "); # 删除WHEN MATCHED后多余的右括号,修正语法 $DbHandle->do(" MERGE INTO THESCHEMA.NAME as t USING session.TEMP_NAME as s ON t.POLICY_MASTER_ID = s.POLICY_MASTER_ID WHEN MATCHED THEN UPDATE SET t.UPDATED_DATETIME = CURRENT_TIMESTAMP WHEN NOT MATCHED THEN INSERT (POLICY_MASTER_ID ) VALUES (s.POLICY_MASTER_ID ) ; "); # 关闭AutoCommit场景下需要手动提交 $DbHandle->commit(); }; if ($@) { # 异常时回滚事务 $DbHandle->rollback() if $DbHandle; print STDERR "ERROR: $ExeName: Cannot merge into ${table} table.\n$@\n"; ExitProc(1); } }
补充说明
- 如果选择关闭
AutoCommit的事务模式,DBI连接初始化时可参考配置:my $DbHandle = DBI->connect($dsn, $user, $pwd, {AutoCommit => 0, RaiseError => 1}),开启RaiseError可以让SQL错误自动抛出,避免异常漏捕获。 - 同一个
$DbHandle连接句柄下,多次do()调用共享同一会话,只要临时表定义时配置了ON COMMIT PRESERVE ROWS,跨do调用访问临时表数据完全正常。
内容的提问来源于stack exchange,提问作者Be Kind To New Users
相关产品推荐
相关产品推荐

