2011-02-24 42 views
18

我想執行匿名PL/SQL並需要獲取結果集對象。我得到了可以通過在PL/SQL塊內使用遊標來完成的代碼。執行匿名PL/SQL塊並獲得結果集在java中

但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; 

任何答覆都會有幫助。

回答

34

這裏是如何「執行匿名PL/SQL,並獲得ResultSet對象」一個自包含的例子

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,從雙重聯合‘你好’名稱選擇2,從雙‘彼得’;」可以通過任何查詢替換

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注入的,當你使用這樣的方法......

+2

匿名塊不能返回一個值。 (SYS_REFCURSOR或其他),它會返回一個PLS-00372錯誤PLS-00372:在一個過程中,RETURN語句不能包含表達式' – 2011-02-24 07:59:09

+0

@Justin:是的,我將它改爲函數。 – ObiWanKenobi 2011-02-24 08:01:00

2

首先,你發佈的代碼是無效的。匿名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>> 
} 
相關問題