不能在 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 查询?的主要内容,如果未能解决你的问题,请参考以下文章

Java JDBC高级特性

2020-2-24

PreparedStatement和Statement

mybatis 查询 orderby

数据库工具类(我老师写的 感觉很好用)

mybatis入门_mybatis基本原理以及入门程序