vogash
vogash

Reputation: 1018

Java Oracle jdbc COLUMN statement

The problem is following By executing the below queries in SQL Plus, everything is working perfect:

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

But when when i tried to execute these queries from Java program, i get 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();
    }

Now the question is how to overcome this error and execute first query or do you have any other solution to define variable on the oracle session and use it in other SQL statements. For instance third query is one of the many queries that i need to execute and all of them will have same first name field

Upvotes: 0

Views: 898

Answers (1)

Justin Cave
Justin Cave

Reputation: 231651

column is a SQL*Plus command. It is not valid in SQL or PL/SQL so you cannot use it in a Java application. Substitution variables like &v_firstname are also a SQL*Plus construct-- they are not valid in SQL or PL/SQL so you cannot use them in a Java application.

If your goal is to get the firstname from tbcustomer and all the columns from tbwork in a single query, you would need to join the two tables. Assuming that both tables have a customer_id column and that is how the two tables are supposed to be joined

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

Assuming that you will be executing this query for multiple customer_id values, however, 111 should be a bind variable instead of a literal and your Java code should be using a PreparedStatement to prepare the SQL statement, then binding a value like 111 using the setInt method before executing the query.

If you want to break this into two database calls, you can simply do something like

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();

If you can guarantee that all 600 million executions will occur in the same database session, you could use a database context. You would need to create the context and the package it uses in the database

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.

From Java, you could then call pkg_get_fname.set_fname(111) to set the context and use the function pkg_get_fname.get_fname in your query.

It seems odd, however, to be concerned about performance and to be planning to execute 600 million queries from Java against the database. That's going to involve a ton of round-trips over the network between the middle tier and the database server-- if you're really concerned about performance, you'd push that work to stored procedures in the database to eliminate the network round-trips. And the fact that you're executing them so many times makes me suspect that you're doing a lot of row-by-row processing rather than letting the database do set-based operations. That's also going to be a major source of poor performance. Plus, databases are born to join, so it's pretty unusual for a simple join like this to add appreciably to the cost of a query assuming that proper indexes are in place.

Upvotes: 4

Related Questions