使用PreparedStatement拼接变量触发java.sql.SQLException的解决办法
问题分析与修复方案
你的代码触发java.sql.SQLException的核心原因是SQL语法错误,同时对PreparedStatement占位符的使用方式有误。咱们一步步拆解问题,再给出修复方案:
为什么原代码会报错?
你写的SQL语句里,'ADMIN_ ||:1||'是被单引号包裹的完整字符串常量——数据库会把||:1||当成字符串的一部分,而不是识别为拼接运算符和占位符。这就导致两个问题:
- 数据库无法解析
||的拼接逻辑,直接抛出语法错误; - 就算语法能过,
PreparedStatement也找不到对应的占位符(因为:1被包在单引号里,不是有效的占位符标识)。
修复方案(两种可选)
方案1:正确使用管道符(||)拼接(适合Oracle等支持该运算符的数据库)
把常量字符串、拼接运算符、占位符分开写,让数据库能识别拼接逻辑:
// 注意:如果是精确匹配用=,模糊匹配用like并按需加通配符 String query = "SELECT count(*) count from apps.fnd_user fu where UPPER(fu.user_name) = 'ADMIN_' || UPPER(:1)"; PreparedStatement stmt = conn.prepareStatement(query); stmt.setString(1, companyName); // 也可以在Java层转大写后传入,减少数据库计算
如果需要模糊匹配(比如匹配以ADMIN_+公司名开头的用户),可以调整为:
String query = "SELECT count(*) count from apps.fnd_user fu where UPPER(fu.user_name) like 'ADMIN_' || UPPER(:1) || '%'";
方案2:在Java层拼接字符串(通用所有数据库)
这种方式更简单,也不用依赖数据库的拼接语法:
String query = "SELECT count(*) count from apps.fnd_user fu where UPPER(fu.user_name) like ?"; PreparedStatement stmt = conn.prepareStatement(query); // 在Java层把前缀和变量拼接好,再传入占位符 stmt.setString(1, "ADMIN_" + companyName.toUpperCase());
如果是模糊匹配,同样可以在Java层加通配符:
stmt.setString(1, "ADMIN_" + companyName.toUpperCase() + "%");
关于管道符的使用
当然可以用管道符(||)进行拼接,但绝对不能把它放在单引号内部——它是SQL的字符串拼接运算符,必须作为SQL语法的一部分存在,而不是字符串常量的内容。只要按照方案1的写法使用,就能正常工作。
内容的提问来源于stack exchange,提问作者Srinivas Pusapati




