【问题标题】:Execute anonymous pl/sql block and get resultset in java执行匿名 pl/sql 块并在 java 中获取结果集
【发布时间】:2011-07-03 08:36:46
【问题描述】:

我想执行匿名 PL/SQL 并需要获取结果集对象。我得到了可以通过在 PL/SQL 块中使用游标来完成的代码。

但是 PL/SQL 块本身将作为文本来自数据库。所以我不能编辑那个 PL/SQL 块。它只会返回两个列名始终相同的值。它将返回 2 列组合值的列表。

我在这里给出示例 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;

任何回复都会很有帮助。

【问题讨论】:

    标签: java jdbc plsql resultset


    【解决方案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();
        }
    }
    

    上面的例子查询“select 1 id, 'hello' name from dual union select 2, 'peter' from dual;”可以被任何查询替换。

    【讨论】:

      【解决方案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 注入...

      【讨论】:

      • 匿名块不能返回值(SYS_REFCURSOR 或其他)。它将返回 PLS-00372 错误 PLS-00372: In a procedure, RETURN statement cannot contain an expression
      • @Justin:没错,我把它改成了一个函数。
      • 甲骨文 11:? := a_sys_ref_cursor ; Oracle >=12 DBMS_SQL.RETURN_RESULT(a_sys_ref_cursor);结束;
      【解决方案3】:

      首先,您发布的代码无效。匿名 PL/SQL 块不能返回表达式。并且没有 PL/SQL 块可以返回这样的查询结果。您需要做一些事情,比如声明一个 REF CURSOR 并使用各种 SQL 语句打开该游标。

      由于匿名 PL/SQL 块无法向调用者返回任何内容,因此您所描述的体系结构存在问题。至少,您需要修改匿名块,以便您的 JDBC 代码可以注册一个绑定变量。类似的东西(改编自Menon's 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>>
      }
      

      【讨论】:

        猜你喜欢
        • 2017-09-02
        • 1970-01-01
        • 1970-01-01
        • 2011-01-10
        • 2017-11-04
        • 2014-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多