0

问题如下通过在 SQL Plus 中执行以下查询,一切正常:

column firstname new_value v_firstname
select firstname from tbcustomer where customer_id = 111
select '&v_firstname', wrk.* from tbwork where customer_id = 111

但是当我尝试从 Java 程序执行这些查询时,我得到java.sql.SQLException: ORA-00900: invalid SQL statement on the first SQL query

        Connection connection = null;
    Statement stat = null;
    String query = "column due_date new_value v_due_date";
    try {

        // Load the JDBC driver
        String driverName = "oracle.jdbc.driver.OracleDriver";
        Class.forName(driverName);
        connection = DriverManager.getConnection(url, username, password);
        stat = connection.createStatement();
        boolean res_num = stat.execute(query);

    } catch (ClassNotFoundException e) {
        // Could not find the database driver
    } catch (SQLException e) {
        e.printStackTrace();
    }

现在的问题是如何克服这个错误并执行第一个查询,或者您是否有任何其他解决方案可以在 oracle 会话上定义变量并在其他 SQL 语句中使用它。例如,第三个查询是我需要执行的众多查询之一,它们都将具有相同的名字字段

4

1 回答 1

4

column是一个 SQL*Plus 命令。它在 SQL 或 PL/SQL 中无效,因此您不能在 Java 应用程序中使用它。类似的替换变量&v_firstname也是一个 SQL*Plus 构造——它们在 SQL 或 PL/SQL 中无效,因此您不能在 Java 应用程序中使用它们。

如果您的目标是在单个查询中获取firstnamefromtbcustomer和所有列tbwork,则需要连接这两个表。假设两个表都有一个customer_id列,这就是应该如何连接两个表

SELECT cust.firstname,
       work.*
  FROM tbcustomer cust
       JOIN tbwork work ON (cust.customer_id = work.customer_id)
 WHERE cust.customer_id = 111

但是,假设您将针对多个customer_id值执行此查询,那么 111 应该是一个绑定变量而不是文字,并且您的 Java 代码应该使用 a来准备 SQL 语句,然后在执行之前PreparedStatement使用该方法绑定一个像 111 这样的值setInt询问。

如果你想把它分成两个数据库调用,你可以简单地做类似的事情

PreparedStatement stmtGetFirstName = connection.prepareStatement("select firstname from tbcustomer where customer_id = ?");
stmtGetFirstName.setInt( 1, 111 );
ResultSet rsGetFirstName = stmtGetFirstName.executeQuery();
String firstName = rsGetFirstName.getString();

PreparedStatement stmtGetWork = connection.prepareStatement("select ?, work.* from tbwork where customer_id = ?");
stmtGetWork.setString( 1, firstName );
stmtGetWork.setInt( 2, 111 );
ResultSet rsGetWork = stmtGetWork.executeQuery();

如果您可以保证所有 6 亿次执行都将发生在同一个数据库会话中,那么您可以使用数据库上下文。您需要创建上下文和它在数据库中使用的包

SQL> create or replace context fname_ctx using scott.pkg_get_fname;

Context created.

SQL> ed
Wrote file afiedt.buf

  1  create or replace package pkg_get_fname
  2  is
  3    procedure set_fname( p_customer_id in number );
  4    function get_fname return varchar2;
  5* end;
SQL> /

Package created.

SQL> create or replace package body pkg_get_fname
  2  is
  3    procedure set_fname( p_customer_id in number )
  4    as
  5    begin
         -- Obviously, you'd get the data here from your table rather than hard-coding 'Bob'
  6      dbms_session.set_context( 'fname_ctx', 'fname', 'Bob' );
  7    end;
  8
  9    function get_fname
 10      return varchar2
 11    is
 12      l_fname varchar2(100);
 13    begin
 14      l_fname := sys_context( 'fname_ctx', 'fname' );
 15      return l_fname;
 16    end;
 17  end;
 18  /

Package body created.

然后,您可以从 Java 调用pkg_get_fname.set_fname(111)以设置上下文并pkg_get_fname.get_fname在查询中使用该函数。

然而,关注性能并计划从 Java 对数据库执行 6 亿次查询似乎很奇怪。这将涉及中间层和数据库服务器之间的大量网络往返——如果你真的关心性能,你会将这项工作推送到数据库中的存储过程以消除网络循环——旅行。而且您多次执行它们的事实使我怀疑您正在执行大量逐行处理,而不是让数据库执行基于集合的操作。这也将成为业绩不佳的主要原因。另外,数据库生来就是为了连接,所以如果有适当的索引,像这样的简单连接会显着增加查询的成本是很不寻常的。

于 2012-06-13T16:52:09.297 回答