IBM i上DB2带输出参数的存储过程始终返回NULL问题排查
问题描述
环境为IBM i上的DB2数据库,使用Run SQL Scripts测试存储过程SGDEDMGT.USPGETBLAHIDFROMBLAHNUM,两种调用方式均返回输出参数BLAHID为<NULL>,但执行返回码为0(执行成功),且已通过SELECT语句确认测试数据确实存在。
调用方式1(带参数初始化)
CALL SGDEDMGT.USPGETBLAHIDFROMBLAHNUM( BLAHNO => 'xx#########00000####', /* IN CHARACTER(20) */ BLAHID => '0' /* OUT INTEGER */ );
执行结果:
[ 09/09/2022, 03:45:30 PM ] Run All...
CALL SGDEDMGT.USPGETBLAHIDFROMBLAHNUM( BLAHNO =>
'xx#########00000####', BLAHID => '0' )
Return Code = 0
Output Parameter #2 (BLAHID) =
Statement ran successfully (141 ms)
调用方式2(最简格式)
CALL SGDEDMGT.USPGETBLAHIDFROMBLAHNUM( 'xx#########00000####',?);
执行结果同样返回BLAHID为<NULL>。
存储过程定义
CREATE PROCEDURE USPGETBLAHIDFROMBLAHNUM ( IN BLAHNO CHAR(20), OUT BLAHID INTEGER ) LANGUAGE SQL P1 : BEGIN DECLARE TMPP INTEGER; SET TMPP = ( SELECT BLAHID FROM SGDEDMGT.BLAHS WHERE "BlahNumber" = BLAHNO ) ; SET BLAHID = TMPP; END P1
原因分析及解决办法
1. CHAR类型的空格填充问题
存储过程输入参数BLAHNO定义为CHAR(20),属于固定长度字符类型。如果传入的字符串'xx#########00000####'长度不足20,DB2会自动在末尾补空格;但如果表SGDEDMGT.BLAHS中的BlahNumber列存储的值无末尾空格(比如列类型为VARCHAR,或存储时未补空格),就会导致WHERE条件不匹配,子查询返回NULL,最终输出参数为NULL。
解决办法:
- 确认传入字符串长度是否为20,不足则手动补空格,例如将调用参数改为
'xx#########00000#### '(补全至20位); - 将存储过程输入参数改为
VARCHAR(20),同时确保表中BlahNumber列类型与参数匹配; - 在WHERE条件中使用
TRIM()函数消除空格影响:WHERE TRIM("BlahNumber") = TRIM(BLAHNO)
2. 列名大小写匹配问题
存储过程WHERE条件使用了带双引号的"BlahNumber",DB2会严格区分大小写匹配列名。如果表SGDEDMGT.BLAHS中的实际列名是全小写(blahnumber)或全大写(BLAHNUMBER),会导致查询不到数据。
解决办法:
- 确认表中列名的实际大小写,将WHERE条件中的列名改为与实际一致;
- 去掉双引号,DB2会自动将列名转换为大写(默认规则),例如改为
WHERE BlahNumber = BLAHNO。
3. 调试验证逻辑
可以在存储过程中添加调试逻辑,确认传入参数的实际值和匹配情况:
P1 : BEGIN DECLARE TMPP INTEGER; -- 调试:输出传入参数的实际值和长度 CALL DB2_SYSIBM.DB2_SQL_DEBUG(CHAR(BLAHNO) || ' Length: ' || CHAR(LENGTH(BLAHNO))); SET TMPP = ( SELECT BLAHID FROM SGDEDMGT.BLAHS WHERE "BlahNumber" = BLAHNO ) ; SET BLAHID = TMPP; END P1
内容的提问来源于stack exchange,提问作者GCDevOps

