Подтвердить что ты не робот

Выполнение анонимного блока pl/sql и получение набора результатов в java

Я хотел бы выполнить анонимный PL/SQL и получить объект resultset. Я получил код, который можно сделать, используя курсоры внутри блока PL/SQL.

Но сам блок PL/SQL будет поступать из базы данных в виде текста. Поэтому я не могу редактировать этот блок PL/SQL. И он вернет только два значения, имена столбцов которых будут одинаковыми всегда. Он вернет список из двух значений комбинации столбцов.

Здесь я даю образец PL/SQL.

BEGIN

RETURN 'select distinct fundname d, fundname r from <table> where condition order by 1';

EXCEPTION
   WHEN OTHERS THEN
    RETURN 'SELECT ''Not Available'' d, ''Not Available'' r FROM dual';
END;

Любой ответ будет настолько полезен.

4b9b3361

Ответ 1

Вот пример использования "анонимного PL/SQL и получения объекта набора результатов"

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Types;

import oracle.jdbc.OracleTypes;

public class CallPLSQLBlockWithOneInputStringAndOneOutputStringParameterAndOneOutputCursorParameter {

    public static void main(String[] args) throws Exception {

        DriverManager.registerDriver(new oracle.jdbc.OracleDriver());

        // Warning: this is a simple example program : In a long running application,
        // error handlers MUST clean up connections statements and result sets.

        final Connection c = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE", "system", "manager");
        String plsql = "" +
        " declare " +  
        "    p_id varchar2(20) := null; " +
        "    l_rc sys_refcursor;" +
        " begin " +
        "    p_id := ?; " +
        "    ? := 'input parameter was = ' || p_id;" +
        "    open l_rc for " +
        "        select 1 id, 'hello' name from dual " +
        "        union " +
        "        select 2, 'peter' from dual; " +
        "    ? := l_rc;" +
        " end;";

        CallableStatement cs = c.prepareCall(plsql);
        cs.setString(1, "12345");
        cs.registerOutParameter(2, Types.VARCHAR);
        cs.registerOutParameter(3, OracleTypes.CURSOR);

        cs.execute();

        System.out.println("Result = " + cs.getObject(2));

        ResultSet cursorResultSet = (ResultSet) cs.getObject(3);
        while (cursorResultSet.next ())
        {
            System.out.println (cursorResultSet.getInt(1) + " " + cursorResultSet.getString(2));
        } 
        cs.close();
        c.close();
    }
}

Вышеупомянутый пример запроса "выберите 1 id, 'hello' name из двойного объединения select 2, 'peter' из double;" может быть заменен любым запросом.

Ответ 2

Попробуйте что-нибудь вроде этого (псевдокод):

[create or replace] function get_dataset (p_query in varchar2) return sys_refcursor
as
  l_returnvalue sys_refcursor;
begin
  open l_returnvalue for p_query;
  return l_returnvalue;
end get_dataset;

Возвращаемый REF CURSOR может обрабатываться как обычный набор данных.

И будьте осторожны с SQL-инъекцией, когда используете такой подход...

Ответ 3

Во-первых, код, который вы опубликовали, недействителен. Анонимный блок PL/SQL не может вернуть выражение. И ни один PL/SQL-блок не может вернуть результат такого запроса. Вам нужно будет сделать что-то вроде объявления REF CURSOR и открытия этого курсора с помощью различных операторов SQL.

Поскольку анонимный блок PL/SQL ничего не может вернуть вызывающему абоненту, описываемая вами архитектура является проблематичной. Как минимум, вам нужно будет изменить анонимный блок, чтобы была зарегистрирована переменная связывания, которую может зарегистрировать код JDBC. Что-то вроде (адаптировано из примера в Menon Expert Oracle JDBC Programming (обратите внимание, что я, возможно, ввел некоторые незначительные синтаксические ошибки)

CallableStatement stmt := null;
ResultSet         rset := null;
String            query := 'DECLARE 
                              FUNCTION get_result
                                RETURN SYS_REFCURSOR
                              AS
                                l_rc SYS_REFCURSOR;
                              BEGIN
                                OPEN l_rc 
                                 FOR SELECT DISTINCT fundname d, fundname r
                                       FROM some_table
                                      WHERE some_condition
                                      ORDER BY 1;
                                RETURN l_rc;
                              EXCEPTION
                                WHEN others THEN
                                  OPEN l_rc 
                                   FOR SELECT 'Not Available' d, 'Not Available' r
                                         FROM dual;
                                  RETURN l_rc;
                              END get_result;
                            BEGIN
                              ? := get_result;
                            END;';
try {
  cstmt := conn.prepareCall( query );
  cstmt.registerOutParameter( 1, OracleTypes.CURSOR );
  cstmt.execute();
  rset := (ResultSet) cstmt.getObject( 1 );
}
finally {
  <<close cstmt & rset>>
}