1. 程式人生 > >Oracle 儲存過程返回陣列記錄集

Oracle 儲存過程返回陣列記錄集

剛學,耗了兩天除錯,寒一個。

  1. 儲存過程:


--建立返回物件型別
CREATE TYPE T_DEPT_NUM_O1 AS OBJECT(
dept_id NUMBER ,
num NUMBER
);
/
--建立臨時表
CREATE type T_DEPT_NUM_T1 as table of T_DEPT_NUM_O1;
/
--建立包
CREATE OR REPLACE PACKAGE KPI_DEPT_EMP_COUNT1 AS



PROCEDURE EmployeeCountProcedure1
(
emp_count out T_DEPT_NUM_T1 --定義返回為臨時表型別
);
end KPI_DEPT_EMP_COUNT1;
/
SHOW ERRORS
/
--建立包體
CREATE OR REPLACE PACKAGE BODY KPI_DEPT_EMP_COUNT1
AS
PROCEDURE EmployeeCountProcedure1 (
emp_count out T_DEPT_NUM_T1


)
IS
deptid number;
i number default 1;
empcount number;

--取得所有有效的部門
cursor c_emp is select sys_org_dept.f_id from sys_org_dept left join sys_org_element on sys_org_element.f_id = sys_org_dept.f_id
where f_isavailable=1 and f_isbusiness = 1;

BEGIN
emp_count := T_DEPT_NUM_T1(); --例項物件
open c_emp;
loop
fetch c_emp into deptid;
if c_emp%notfound then

DBMS_OUTPUT.PUT('======not found=======');
end if;
exit when c_emp%notfound;
--遞迴查詢部門下的所有人數
select to_number(count(*)) into empcount from sys_org_element
where sys_org_element.f_orgtype=8 and f_isavailable=1 and f_isbusiness = 1
start with f_id = deptid connect by prior f_id = f_parentdeptid
;
emp_count.extend; --擴充套件臨時表 表裡面放自定義物件


emp_count(i) := T_DEPT_NUM_O1(deptid,empcount);

DBMS_OUTPUT.PUT('the gains that DEPT_ID:');
DBMS_OUTPUT.PUT(deptid);
DBMS_OUTPUT.PUT(' NUM:');
DBMS_OUTPUT.PUT(empcount);
dbms_output.new_line();

i := i + 1;
end loop;
close c_emp; 

END EmployeeCountProcedure1;
END KPI_DEPT_EMP_COUNT1;
/
SHOW ERRORS
/
 

2.sqlplus驗證

SET SERVEROUTPUT ON;
--檢視結果
declare

emp_count T_DEPT_NUM_T1 := T_DEPT_NUM_T1();
begin
KPI_DEPT_EMP_COUNT1.EmployeeCountProcedure1(emp_count);
end;
/
SHOW ERRORS
/

3.spring中呼叫儲存過程

private class DepartmentEmployeeCountProcedure extends StoredProcedure {

public DepartmentEmployeeCountProcedure(DataSource ds) {
setDataSource(ds);
setJdbcTemplate(new JdbcTemplate(ds));
getJdbcTemplate().setNativeJdbcExtractor(nativeJdbcExtractor);
setSql(PROC_NAME);

declareParameter(new SqlOutParameter("emp_count",Types.ARRAY, "T_DEPT_NUM_T1"));
compile();
}

public Map execute() {
Map out = new HashMap();
try {
Map result = new HashMap();
result = execute(new HashMap());
ARRAY arr = (ARRAY) result.get("emp_count");
ResultSet rs = arr.getResultSet();
while (rs.next()){
STRUCT struct = (STRUCT)rs.getObject(2);
Object[] obs = struct.getAttributes();
out.put(obs[0].toString(),new Double(((BigDecimal)obs[1]).doubleValue()));
System.out.println(obs[0] + " " +obs[0].getClass());
System.out.println(obs[1] + " " +obs[1].getClass());
}
} catch (CannotGetJdbcConnectionException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

return out;
}

}

4.除錯過程出現的錯誤:

  • 內部錯誤: Image is a collection image, expecting ADT
    有人說是Oracle9的bug,刪除所有型別並將使用的型別重新改名就好了,可是我照做了也還是不行,後來添加了方法: setJdbcTemplate(new JdbcTemplate(ds));
    getJdbcTemplate().setNativeJdbcExtractor(nativeJdbcExtractor);
    並修改了返回型別為:Types.ARRAY(原來使用 OracleTypes.STRUCT)就行了。不過這時候我的使用型別名稱也已經改掉了。
  • java.lang.AbstractMethodError: oracle.jdbc.driver.OracleConnection.getTypeMap()Ljava/util/Map;
    不知道原因的錯誤,出現在定義資料庫型別時。定義資料庫返回型別的變數如下:
    SqlReturnType param = new SqlReturnType() {

    public Object getTypeValue(CallableStatement cs, int paramIndex,
    int sqlType, String typeName) throws SQLException {
    Connection con = cs.getConnection();
    oracle.jdbc.driver.OracleConnection connection = (oracle.jdbc.driver.OracleConnection)con;

    Dictionary d = connection.getTypeMap();
    // if((con instanceof oracle.jdbc.driver.OracleConnection)){
    // con = nativeJdbcExtractor.getNativeConnection(con);
    // System.out.println("=================================");
    // }
    // Map typeMap = con.getTypeMap();
    d.put(typeName, PersonCount.class);
    Object o = cs.getObject(paramIndex);
    return o;
    }

    };
    在不管是使用Connection還是使用OracleConnection,在呼叫getTypeMap()時總會出現此錯誤。使用nativeJdbcExtractor獲得的連線不會出現此錯誤,不過好像型別轉換無效,取到的結果還是原來的ARRAY裡面包含STRUCT物件。

5.除錯時一些參考資料: