DB2 for i存储过程传入逗号分隔字符串在NOT IN子句失效问题
解决DB2 for i存储过程中NOT IN子句不生效的问题
我明白你现在遇到的困扰——明明传了逗号分隔的多个值,结果NOT IN根本没起到过滤作用,反而把整个字符串当成一个值存进了表字段里。这其实是因为你传递的参数格式和SQL解析逻辑不匹配导致的,咱们一步步来解决:
问题根源
你现在在Java里传的是'232/232','34fd/34//',这个字符串到了存储过程的code参数里,SQL会把它当成一个完整的字符串值。也就是说,你的NOT IN子句实际变成了:
table2.status not in ('\'232/232\',\'34fd/34//\'')
相当于你在找status等于这个超长字符串的记录,自然不会过滤掉任何单个的status值。
推荐解决方案(安全无注入风险)
方法1:使用STRTOK_TABLE表函数拆分字符串(DB2 for i 7.1及以上支持)
这个方法最简洁,利用DB2自带的表函数把逗号分隔的字符串拆分成独立的行,再用这些行作为NOT IN的条件。
首先修改存储过程的SQL逻辑:
create procedure history (in id varchar (3), in code varchar (2000)) begin insert into table1 select date_from, date_to, code from table2 where table2.serial = id and table2.status not in ( -- 按逗号拆分code参数,取出每个独立的token select token from table(STRTOK_TABLE(code, ',')) ); end
然后调整Java里的参数,去掉多余的单引号,只保留逗号分隔的原始值:
String codeString = "232/232,34fd/34//";
方法2:使用XMLTABLE拆分字符串(兼容更低版本DB2)
如果你的DB2版本不支持STRTOK_TABLE,可以用XMLTABLE来实现拆分:
create procedure history (in id varchar (3), in code varchar (2000)) begin insert into table1 select date_from, date_to, code from table2 where table2.serial = id and table2.status not in ( -- 把逗号替换成XML格式的分隔符,再解析成行 select trim(x.column_value) from xmltable(('"' || replace(code, ',', '","') || '"')) as x ); end
Java端的参数同样需要改成不带单引号的逗号分隔字符串:
String codeString = "232/232,34fd/34//";
不推荐的方法(存在SQL注入风险)
如果你确定参数绝对安全(比如不是用户输入的内容),可以用动态SQL拼接语句,但这个方法有严重的注入风险,谨慎使用:
create procedure history (in id varchar (3), in code varchar (2000)) begin declare sql_stmt varchar(4000); -- 直接拼接code参数到SQL语句中 set sql_stmt = 'insert into table1 select date_from, date_to, code from table2 where table2.serial= ? and table2.status not in (' || code || ')'; prepare stmt from sql_stmt; execute stmt using id; end
这种情况下Java端可以保留原来的带单引号的参数格式,但强烈不建议在生产环境使用。
内容的提问来源于stack exchange,提问作者bkashaf




