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 プログラムからこれらのクエリを実行しようとすると、最初の SQL クエリでjava.sql.SQLException: ORA-00900: invalid SQL statementが発生します。

        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 ステートメントで使用する他の解決策があるかどうかです。たとえば、3 番目のクエリは、実行する必要がある多くのクエリの 1 つであり、それらはすべて同じ名前フィールドを持ちます。

4

1 に答える 1

4

columnSQL*Plus コマンドです。SQL または PL/SQL では有効ではないため、Java アプリケーションでは使用できません。のような置換変数&v_firstnameも SQL*Plus 構造です。これらは SQL または PL/SQL では有効ではないため、Java アプリケーションでは使用できません。

firstname単一のクエリでfromtbcustomerとすべての列を取得することが目的の場合はtbwork、2 つのテーブルを結合する必要があります。両方のテーブルにcustomer_id列があり、それが2つのテーブルが結合される方法であると仮定します

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 コードは を使用しPreparedStatementて SQL ステートメントを準備し、setIntメソッドを使用して 111 のような値をバインドしてから、クエリ。

これを 2 つのデータベース呼び出しに分割したい場合は、単純に次のようにすることができます。

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 に答える