You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PreparedStatement绑定IN参数报ORA-01722无效数字错误如何解决

报错根因
  1. 你当前的传参逻辑触发了Oracle的类型转换错误:AGRID是数值类型字段,你传入的是用逗号拼接的整串字符串(例如"1,2,3"),Oracle尝试将整个带逗号的字符串转为数值时失败,抛出ORA-01722: invalid number错误。
  2. 本质是对PreparedStatement占位符的逻辑理解错误:单个占位符?只能对应单个参数值,无法直接匹配IN子句需要的多个值列表,你把拼接好的整个值列表当成单个参数传入,属于错误的传参方式。
正确实现方式

方式一:动态生成对应数量的占位符(通用方案,兼容所有数据库)

这是最常用的无SQL注入风险的实现方案:

  1. 先调整SQL模板,把IN子句的占位符部分改为可替换的模板标记:
<entry key="GET DATA">
select ATYPE, ANAME, AGRID, AVALUE
from ALG_RSV.TERMS
where AGRID in (%s)
order by 2,1
</entry>
  1. 代码中根据参数列表的长度动态生成对应数量的占位符,再循环给每个占位符赋值:
List<String> agreeIDs = getAgree();
// 生成和参数数量匹配的占位符串,例如3个参数就生成 ?,?,?
String placeholders = String.join(",", Collections.nCopies(agreeIDs.size(), "?"));
// 拼装最终SQL
String sqlTemplate = CSRConsole.getProperty("GET DATA");
String sqlQuery = String.format(sqlTemplate, placeholders);

prepStat = Conn.prepareStatement(sqlQuery);
// 循环给每个占位符赋值,注意占位符下标从1开始
for (int i = 0; i < agreeIDs.size(); i++) {
    // 如果AGRID是数值类型,这里改成prepStat.setInt(i+1, Integer.parseInt(agreeIDs.get(i)))
    prepStat.setString(i+1, agreeIDs.get(i));
}
rs = prepStat.executeQuery();

方式二:使用Oracle原生字符串拆分函数(固定SQL结构方案)

如果不想动态拼接SQL结构,可以使用Oracle的XMLTABLE函数拆分传入的逗号分隔字符串为行,再做匹配:

  1. 调整SQL模板:
<entry key="GET DATA">
select ATYPE, ANAME, AGRID, AVALUE
from ALG_RSV.TERMS
where AGRID in (
    select to_number(column_value) from xmltable(:agr_ids)
)
order by 2,1
</entry>
  1. 代码直接传入拼接好的字符串即可:
String agrID = String.join(",", agreeIDs);
prepStat = Conn.prepareStatement(sqlQuery);
prepStat.setString(1, agrID);
rs = prepStat.executeQuery();
注意事项

Oracle的IN子句默认最多支持1000个参数,如果你的agreeIDs长度超过1000,需要把列表拆分为多批查询,或者改用临时表关联、子查询等方式实现。

内容的提问来源于stack exchange,提问作者Charu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 19:24:04