【问题标题】:Cannot use a LIKE query in a JDBC PreparedStatement?不能在 JDBC PreparedStatement 中使用 LIKE 查询?
【发布时间】:2023-04-09 13:24:01
【问题描述】:

查询代码及查询:

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 行代码的报告页面,其中应用程序架构有点矫枉过正:) 但我很欣赏你的观点!

标签: java oracle jdbc sql-like


【解决方案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%");

另见

【讨论】:

    【解决方案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】:

          这应该可行:

          "\'" + "?" + "\'"
          

          【讨论】:

            猜你喜欢
            • 2019-11-21
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-03-15
            • 2021-07-28
            • 1970-01-01
            • 1970-01-01
            • 2011-10-02
            相关资源
            最近更新 更多