【问题标题】:Sql query with bind variables execution in Jdbc在 Jdbc 中执行绑定变量的 Sql 查询
【发布时间】:2014-01-03 11:29:21
【问题描述】:

我有一个这样的 sql 查询。

 select "DEPT"."DEPTNO" as "DEPTNO1",
"DEPT"."DNAME" as "DNAME1",
"DEPT"."LOC" as "LOC1",
"EMP"."COMM" as "COMM1",
"EMP"."EMPNO" as "EMPNO1",
"EMP"."ENAME" as "ENAME1",
"EMP"."HIREDATE" as "HIREDATE1",
"EMP"."JOB" as "JOB1",
"EMP"."MGR" as "MGR1",
"EMP"."SAL" as "SAL1"
from "EMP" , "DEPT" where "DEPT"."DEPTNO" in (:DeptNo)

//这是Jdbc代码

Class.forName(DB_DRIVER);
dbConnection = DriverManager.getConnection(DB_CONNECTION, DB_USER, DB_PASSWORD);
Statement statment = dbConnection.createStatement();
result = statment.execute(query);//query is above sql query

当我在 Oracle sql developer 中运行上面的查询时,效果很好。但是当我使用上面的 jdbc 代码运行它时,它会抛出 Not all variables bound exception。 如何在 JDBC 中运行上述查询

【问题讨论】:

  • 张贴你得到的确切错误。发布堆栈跟踪。贴出你拥有的所有代码。
  • 您的查询中有一个命名参数 (:DeptNo),但您没有为其分配值。
  • ORA-01008:并非所有变量都绑定。当我在 JDBC 中运行以上 sql 查询时遇到此错误
  • 我想像使用 JDBC 一样执行查询
  • 以上查询在 Oracle Sql 开发者中完美运行,而不是在 Jdbc 中。

标签: java sql oracle jdbc


【解决方案1】:

将查询中的 :deptno 替换为 ?。

使用以下语句代替实例化语句:

PreparedStatement stmt=con.prepareStatement(query);

stmt.setInt(1,deptno); //1 is for the first question mark

其中deptno 保存您要执行查询的值。

通过 PrepredStatement 接口,我们可以使用参数化查询,它只编译一次,与 Statement 接口相比具有性能优势。

【讨论】:

  • 运行时,即使我不知道查询有多少绑定变量。
  • 您上面提到的查询只有一个绑定变量,即 :deptno 您不确定查询吗?
  • 提到了一个示例查询,在运行时我会得到更多没有。可能包含多个绑定变量的查询
  • 请问查询的来源是什么?或者查询是如何生成的以及何时更改?
  • 查询是根据报告生成的,我们不知道它有多少绑定变量。根据报告,查询将发生变化。
【解决方案2】:

您使用绑定变量创建了一个查询,但您从未设置它。

使用OraclePreparedStatement及其方法setStringAtName()

statement.setStringAtName("DeptNo","<<your Value>>");

如果不是OraclePreparedStatement,您可以将其作为?1 放在查询字符串中 并使用,

statement.setString(1,"<<your Value>>");

如果您不知道获得了多少绑定变量,您可以在映射中捕获绑定变量并准备一个列表并进行相应的设置!

否则您的要求无法实现!

【讨论】:

  • OraclePreparedStatement prestmt = (OraclePreparedStatement)dbConnection.prepareStatement(query); prestmt.setStringAtName("DeptNo","DeptNo"); result = prestmt.execute(query);//throw 尝试设置SQL中没有出现的参数名:DeptNo
  • 请打印您的查询字符串并确认绑定变量的名称。它区分大小写。
【解决方案3】:

使用此语法EMP.DNAME as DNAME1。我的意思是你的点和 as 必须在双引号内。

【讨论】:

    【解决方案4】:

    从报告中动态获取查询。

    从这个查询中,我们需要拆分查询字符串以获取绑定变量的数量,并将这些绑定变量放在 HashMap 中。HashMap 就像

                {DeptName =1, Job =1, DeptNo =1}
    

    从这个hashmap中,需要用?替换查询绑定变量。为此我们需要这样做

       bindkey = entry1.getKey().toString();
        String bindkeyreplace =":".concat(bindkey).trim();
        String bindkeyreplacestring = "?";
        query = query.replace(bindkeyreplace, bindkeyreplacestring);
    

    然后我们将得到来自报告的动态查询?而不是:bindvariable

            PreparedStatement prestmt = dbConnection.prepareStatement(query);
            for (int i = 0; i < bindParamMap.size(); i++) {
                 prestmt.setInt(i + 1, 0);//Setting default value to check the query is running successfully or not
            }
            result = prestmt.execute();
    

    如果我们不知道我们得到了多少绑定变量,那么这种方法对我来说是成功的。

    【讨论】:

      【解决方案5】:

      在执行如下语句之前,必须将变量 DeptNo 绑定到一个值。

      DriverManager.getConnection(DB_CONNECTION, DB_USER, DB_PASSWORD);
      Statement statment = dbConnection.createStatement();
      //Bind deptno to a value
      statment.setParameter("DeptNo",5);
      result = statment.execute(query);    
      

      您必须为准备好的语句中的所有变量设置值,否则您无法执行该语句。如果您收到将自身作为输入执行的查询,那么您还应该将参数及其值也作为输入。类似下面的东西

      public <returnType> executeQuery(String queryStr, Map<String,Object> params) {
           //Code to create connecitno and statment from queryStr.
           //Bind deptno to a value
           for(int i=0;i<params.size(),i++) {
             //Get entry set from map  
             statment.setParameter(entryset.getKey(),entryset.getValue());
           }
      
           result = statment.execute(query);
           //return or work on the result      
      }
      

      【讨论】:

      • 但是在运行时我会得到更多的查询,甚至我不知道会有多少绑定变量。
      • 这个方法是否存在 setParameter()?
      • setParameter 不直接存在于 PreparedStatement 中。看看stackoverflow.com/questions/2309970/named-parameters-in-jdbcjavaworld.com/article/2077706/core-java/… 来模仿那个设施。
      • @thiyaga 你怎么写statment.setParameter()
      • @JqueryLearner,这只是一个编写的wapper方法。实际方法将是 setInt 或 setString 或 SetObject 等。我们可以编写一个名为 setParameter 的包装方法,它检查参数的类类型并利用准备好的语句上的相应方法。
      猜你喜欢
      • 1970-01-01
      • 2021-10-27
      • 2014-04-29
      • 1970-01-01
      • 1970-01-01
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多