Выполнить анонимный блок pl / sql и получить набор результатов в Java - PullRequest
21 голосов
/ 24 февраля 2011

Я хотел бы выполнить анонимный PL / SQL и мне нужно получить объект результирующего набора. Я получил код, который можно сделать с помощью курсоров внутри блока 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;

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

Ответы [ 3 ]

39 голосов
/ 05 мая 2012

Вот автономный пример того, как «выполнить анонимный 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 идентификатор, имя« привет »из двойного объединения»выберите 2, 'peter' из dual; "можно заменить любым запросом.

3 голосов
/ 24 февраля 2011

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

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

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>>
}
3 голосов
/ 24 февраля 2011

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

[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-инъекций , когда вы используете такой подход ...

...