不能在 JDBC PreparedStatement 中使用 LIKE 查询?
Posted
技术标签:
【中文标题】不能在 JDBC PreparedStatement 中使用 LIKE 查询?【英文标题】:Cannot use a LIKE query in a JDBC PreparedStatement? 【发布时间】:2011-02-20 21:05:44 【问题描述】:查询代码及查询:
ps = conn.prepareStatement("select instance_id, ? from eam_measurement where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where resource_group_id = ?) and DSN like '?' order by 2");
ps.setString(1,"SUBSTR(DSN,27,16)");
ps.setInt(2,defaultWasGroup);
ps.setString(3,"%Module=jvmRuntimeModule:freeMemory%");
rs = ps.executeQuery();
while (rs.next()) bla blah blah blah ...
返回一个空的ResultSet
。
通过基本调试,我发现它的第三个绑定是问题,即
DSN like '?'
我尝试了各种变体,其中最明智的似乎是使用:
DSN like concat('%',?,'%')
但这不起作用,因为我错过了连接字符串两侧的'
,所以我尝试:
DSN like ' concat('%',Module=P_STAG_JDBC01:poolSize,'%') ' order by 2
但我似乎无法找到让他们参与其中的方法。
我错过了什么?
【问题讨论】:
在 JSP 文件中而不是在真正的 Java 类中编写 Java 代码(您应该已经这样做了)并且遇到特定 Java 代码的问题不会成功一个 JSP 问题。在真正的 Java 类中这样做时,您将面临完全相同的问题。所以我删除了[jsp]
标签,因为这无关紧要。
确实它不是特定于 JSP 的,但是根据我读过的大多数书籍,在 servlet 中使用这样的代码并没有什么错误,尤其是当它超级简单的时候少于 40 行代码的报告页面,其中应用程序架构有点矫枉过正:) 但我很欣赏你的观点!
【参考方案1】:
首先,PreparedStatement
占位符(那些?
事物)仅用于列值,不适用于表名、列名、SQL 函数/子句等。最好改用String#format()
。其次,您应该不引用 '?'
之类的占位符,它只会导致最终查询的格式错误。 PreparedStatement
setter 已经为您完成了引用(和转义)工作。
这是固定的 SQL:
private static final String SQL = "select instance_id, %s from eam_measurement"
+ " where resource_id in (select RESOURCE_ID from eam_res_grp_res_map where"
+ " resource_group_id = ?) and DSN like ? order by 2");
这里是如何使用它:
String sql = String.format(SQL, "SUBSTR(DSN,27,16)"); // This replaces the %s.
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, defaultWasGroup);
preparedStatement.setString(2, "%Module=jvmRuntimeModule:freeMemory%");
另见:
Sun JDBC tutorial: Using Prepared Statements Format string syntax【讨论】:
【参考方案2】:如果你想在准备好的语句中使用 LIKE 并且还想在 LIKE 中使用 % 字符;
像往常一样编写准备好的语句“ .... LIKE ? ....”,并在将参数值分配给问号使用时
ps.setString(1, "%" + "your string value" + "%");
这会起作用:)
【讨论】:
【参考方案3】:你的陈述有两个问题。您必须了解绑定变量的工作原理。查询不会通过用您的参数替换字符 ?
来处理。而是使用占位符编译语句,然后在执行期间将参数的实际值提供给 DB。
换句话说,您解析以下查询:
SELECT instance_id, :p1
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = :p2)
AND DSN LIKE '?'
ORDER BY 2
我很确定最后一个参数将被忽略,因为它位于分隔字符串中。即使它没有被忽略,使用'
字符也是没有意义的,因为Oracle 不会在字符串中绑定参数(我很惊讶它没有引发任何错误,你捕获异常了吗?)。
现在,如果您将 DNS LIKE '?'
替换为 DSN LIKE ?
并绑定 "%Module=jvmRuntimeModule:freeMemory%"
,这将是有意义的,并且应该返回正确的行。
您的第一个参数仍然有问题,它不会按照您的预期执行,即将执行的查询将等同于以下查询:
SELECT instance_id, 'SUBSTR(DSN,27,16)'
FROM ...
和
完全不一样SELECT instance_id, SUBSTR(DSN,27,16)
FROM ...
如果您希望 SUBSTR 是动态的,我建议您解析 (=prepareStatement) 以下查询:
SELECT instance_id, SUBSTR(DSN,?,?)
FROM eam_measurement
WHERE resource_id IN (SELECT RESOURCE_ID
FROM eam_res_grp_res_map
WHERE resource_group_id = ?)
AND DSN LIKE ?
ORDER BY 2
【讨论】:
【参考方案4】:省略?
周围的'
。如果没有'
,?
是参数的占位符。有了它,它就是一个 SQL 字符串(即与 Java 中的 "?"
相同)。
那么你必须在Java端连接字符串;您不能将 SQL 函数作为参数传递给查询;只有基本值(如字符串、整数等),因为 JDBC 驱动程序会将参数转换为数据库期望的 SQL 类型,并且在此步骤中无法执行 SQL 函数。
【讨论】:
在 ? 周围没有 ''我也得到一个空的结果集。毫不奇怪,我猜当时 sql 会读取:和 DSN like %Module=P_STAG_JDBC01:poolSize% 哪个 oracle 不喜欢并回复:Missing IN or OUT parameter at index:: 1 (error code=17041) 因此我需要当我通过 ps.setString 设置时,将 ''s 添加到绑定中? 例如ps.setString(3,"'Module=jvmRuntimeModule:freeMemory'");但也给出了一个空的结果集, ps.setString(3,"\'Module=jvmRuntimeModule:freeMemory\'");尽管 java 文档说没有必要在 ""s 中转义 ' @SeerUK:错误信息来自参数1,而不是来自参数3!【参考方案5】:你可以试试:
String beforeAndAfter = "%" + yourVariable + "%";
【讨论】:
【参考方案6】:PreparedStatement ps = con.prepareStatement(
"select columname from tablename where LOWER(columnname) LIKE LOWER('"+var+"%')");
这里var
是存储要搜索的值的变量...
【讨论】:
请提供更多解释并格式化您的代码(您可以使用“反引号”或缩进 4 个空格)。 How to Answer【参考方案7】:这应该可行:
"\'" + "?" + "\'"
【讨论】:
以上是关于不能在 JDBC PreparedStatement 中使用 LIKE 查询?的主要内容,如果未能解决你的问题,请参考以下文章