Chinaunix首页 | 论坛 | 博客
  • 博客访问: 409849
  • 博文数量: 66
  • 博客积分: 1416
  • 博客等级: 上尉
  • 技术积分: 922
  • 用 户 组: 普通用户
  • 注册时间: 2006-09-16 10:37
个人简介

高級Oracle DBA,善長Linux系統維運以及Oracle數據庫管理,開發,調優. 具有多年PL/SQL開發經驗.

文章分类

全部博文(66)

文章存档

2015年(9)

2014年(4)

2013年(5)

2010年(1)

2009年(3)

2008年(6)

2007年(30)

2006年(8)

我的朋友

分类: Oracle

2015-09-08 14:05:12

之前有使用plsq package 封裝java jxl, 用來解析Microsoft Excel 97/2000文檔.
為對比性能, 又使用apache poi重新封裝了一個,接口一致的版本.

效果圖如下


oracle package poi_hssf,  pl/sql封裝.

点击(此处)折叠或打开

  1. CREATE OR REPLACE PACKAGE poi_hssf authid definer as
  2. /****************************************************************************
  3.    Ver Date Author Description
  4.    --------- ---------- --------------- --------------------------------------------
  5.    1.0 2015-04-12 gangjh 1. 使用java poi hssf 訪問blob的excel 2000數據.
  6.                                                返回table類型數據.

  7. *******************************************************************************/

  8.   SUBTYPE ctxHandle IS binary_integer;
  9.   subtype celltype is varchar2(4000 byte) ; -- limit for oracle 10g

  10.   SUBTYPE error_code_type IS BINARY_INTEGER;
  11.   SUBTYPE error_message_type IS VARCHAR2(1000);

  12.   type cell_val is record (
  13.   sheet int,
  14.   row_idx int,
  15.   col_idx int,
  16.   data celltype
  17.   ) ;
  18.   type xls_data is table of cell_val ;
  19.   c_max_cols constant pls_integer := 20;

  20.   type xls_row is record (
  21.     sheet int ,
  22.     row_idx int ,
  23.     col_a celltype,
  24.     col_b celltype,
  25.     col_c celltype,
  26.     col_d celltype,
  27.     col_e celltype,
  28.     col_f celltype,
  29.     col_g celltype,
  30.     col_h celltype,
  31.     col_i celltype,
  32.     col_j celltype,
  33.     col_k celltype,
  34.     col_l celltype,
  35.     col_m celltype,
  36.     col_n celltype,
  37.     col_o celltype,
  38.     col_p celltype,
  39.     col_q celltype,
  40.     col_r celltype,
  41.     col_s celltype,
  42.     col_t celltype
  43.   );

  44.   type xls_table is table of xls_row ;


  45. PROCEDURE raise_error_if_failure
  46.   (
  47.     error_code ERROR_CODE_TYPE,
  48.     error_message ERROR_MESSAGE_TYPE
  49.   ) ;



  50. /****************************************
  51.  with xt as
  52. ( select a.id,a.name ,xx.*
  53.     from xmldata a,
  54.     table( poi_hssf.get_xls_val(blob_temp) ) xx
  55.     where a.name='MSOFFICE.EXCEL'
  56. )

  57. select id,name,sheet,row_idx,
  58. max(decode(col_idx,0,data,'')) col0,
  59. max(decode(col_idx,1,data,'')) col1,
  60. max(decode(col_idx,2,data,'')) col2
  61. from xt
  62. group by id,name,sheet,row_idx;
  63. ************************/

  64.   function get_xls_val(data in blob) RETURN xls_data PIPELINED ;


  65. /*********************************************
  66. ex1:
  67.   select a.id,xx.*,a.name
  68.     from xmldata a,
  69.     table( poi_hssf.get_xls_table(blob_temp) ) xx
  70.     where a.name='MSOFFICE.EXCEL' and id=23 and sheet=4

  71. ex2:
  72. select * from table(poi_hssf.get_xls_table(utl_lob.url2blob('ftp://172.17.2.43/pub/test001.xls')))

  73. ************************************/

  74. -- p_sheet := -1 : select all sheet
  75. /* function get_xls_table(p_data in blob, p_sheet int default -1 ) RETURN xls_table2 PIPELINED ;

  76.   function get_xls_table(p_data in blob, p_sheet int default -1 ) RETURN xls_table PIPELINED ;
  77. */

  78.   function get_xls_table(p_data in blob, p_sheet int default -1) RETURN xls_table PIPELINED;


  79.   PROCEDURE poitest(vfile varchar2);


  80. END poi_hssf;
  81. /
  82. CREATE OR REPLACE PACKAGE body poi_hssf AS
  83.   excel_parsing_error EXCEPTION;
  84.     pragma EXCEPTION_INIT(excel_parsing_error, -29532);

  85.   SUCCESS CONSTANT BINARY_INTEGER := 0;


  86. /**************** java implement ****************************/
  87.   FUNCTION newContext_java(data IN blob, error_code OUT ERROR_CODE_TYPE, error_message OUT error_message_type) RETURN ctxHandle
  88.   as LANGUAGE JAVA NAME
  89.    'corp.poi.ExcelUtilWithHSSF.newcontext(oracle.sql.BLOB, int[], java.lang.String[]) return int';

  90.   PROCEDURE closeContext(ctx IN ctxHandle)
  91.   as LANGUAGE JAVA NAME
  92.    'corp.poi.ExcelUtilWithHSSF.closecontext(int)';

  93.   function getSheets(ctx IN ctxHandle) return binary_integer
  94.   as LANGUAGE JAVA NAME
  95.    'corp.poi.ExcelUtilWithHSSF.getSheets(int) return int';

  96.   function selectSheet(ctx IN ctxHandle, sheet binary_integer) return binary_integer
  97.   as LANGUAGE JAVA NAME
  98.    'corp.poi.ExcelUtilWithHSSF.selectSheet(int, int) return int';


  99.   function getFirstRowNum(ctx IN ctxHandle) return binary_integer
  100.   as LANGUAGE JAVA NAME
  101.    'corp.poi.ExcelUtilWithHSSF.getFirstRowNum(int) return int';

  102.   function getLastRowNum(ctx IN ctxHandle) return binary_integer
  103.   as LANGUAGE JAVA NAME
  104.    'corp.poi.ExcelUtilWithHSSF.getLastRowNum(int) return int';
  105.    

  106.   function getColumns(ctx IN ctxHandle, prow binary_integer) return binary_integer
  107.   as LANGUAGE JAVA NAME
  108.    'corp.poi.ExcelUtilWithHSSF.getColumns(int, int) return int';

  109.  -- for cell data length >4000 byte
  110.   procedure getClob(ctx IN ctxHandle, p_row in binary_integer, p_col in binary_integer, p_clob in out nocopy clob)
  111.   as LANGUAGE JAVA NAME
  112.    'corp.poi.ExcelUtilWithHSSF.getClob(int, int, int, oracle.sql.CLOB[])';

  113. -- Oracle has a limit of 4000 bytes for a VARCHAR2, >4000 will by trim
  114.   FUNCTION getString(ctx IN ctxHandle, p_row in binary_integer, p_col in binary_integer) RETURN varchar2
  115.   as LANGUAGE JAVA NAME
  116.    'corp.poi.ExcelUtilWithHSSF.getString(int, int, int) return java.lang.String';

  117.   function getSheetCount(ctx IN ctxHandle) return binary_integer
  118.   as LANGUAGE JAVA NAME
  119.    'corp.poi.ExcelUtilWithHSSF.getSheetCount(int) return int';

  120. /*********************************************/


  121.   PROCEDURE raise_error_if_failure(error_code ERROR_CODE_TYPE,
  122.                                     error_message ERROR_MESSAGE_TYPE)
  123.   IS
  124.   BEGIN
  125.     IF error_code <> SUCCESS THEN
  126.       raise_application_error(error_code, error_message);
  127.     END IF;
  128.   END;

  129.   FUNCTION newContext(data IN blob) RETURN ctxHandle
  130.   IS
  131.    error_code ERROR_CODE_TYPE;
  132.    error_message ERROR_MESSAGE_TYPE;
  133.    v_ctx ctxHandle;
  134.   BEGIN
  135.     v_ctx := newContext_java(data, error_code, error_message);
  136.     raise_error_if_failure(error_code, error_message);
  137.     return v_ctx;
  138.   end ;


  139.   function get_xls_val(data in blob) RETURN xls_data PIPELINED
  140.   is
  141.   ctx poi_hssf.ctxHandle ;
  142.   r int ;
  143.   sheet_cnt pls_integer ;
  144.   col_cnt pls_integer;
  145.   cell cell_val ;
  146.   v_ret binary_integer;
  147.   begin
  148.     ctx := newcontext(data) ;

  149.     sheet_cnt := getSheets(ctx) ;
  150.     for s in 0.. sheet_cnt-1 loop --多個excel sheet
  151.       cell.sheet := s;
  152.       v_ret := selectSheet(ctx, s) ;

  153.       for r in getFirstRowNum(ctx)..getLastRowNum(ctx) loop --sheet中抓每一行
  154.         col_cnt := getColumns(ctx, r) ;
  155.         cell.row_idx :=r ;
  156.         for c in 0..col_cnt-1 loop --每行的每一列
  157.           cell.col_idx := c;
  158.           cell.data := getString(ctx, r, c) ;
  159.           pipe row (cell);
  160.         end loop;
  161.       end loop;
  162.     end loop;
  163.     closeContext(ctx) ;
  164.     return;

  165.    exception
  166.       when NO_DATA_NEEDED then
  167.           poi_hssf.closeContext(ctx) ;
  168.   end get_xls_val;




  169. procedure get_xls_row_val(p_row in out xls_row, ctx ctxHandle, row_idx pls_integer, maxcol pls_integer) is
  170.   v_cellval celltype ;
  171.   procedure fill_cell(v_cellval celltype, c pls_integer) is
  172.   begin
  173.     case
  174.       when c=0 then p_row.col_a := v_cellval ;
  175.       when c=1 then p_row.col_b := v_cellval ;
  176.       when c=2 then p_row.col_c := v_cellval ;
  177.       when c=3 then p_row.col_d := v_cellval ;
  178.       when c=4 then p_row.col_e := v_cellval ;
  179.       when c=5 then p_row.col_f := v_cellval ;
  180.       when c=6 then p_row.col_g := v_cellval ;
  181.       when c=7 then p_row.col_h := v_cellval ;
  182.       when c=8 then p_row.col_i := v_cellval ;
  183.       when c=9 then p_row.col_j := v_cellval ;
  184.       when c=10 then p_row.col_k := v_cellval ;
  185.       when c=11 then p_row.col_l := v_cellval ;
  186.       when c=12 then p_row.col_m := v_cellval ;
  187.       when c=13 then p_row.col_n := v_cellval ;
  188.       when c=14 then p_row.col_o := v_cellval ;
  189.       when c=15 then p_row.col_p := v_cellval ;
  190.       when c=16 then p_row.col_q := v_cellval ;
  191.       when c=17 then p_row.col_r := v_cellval ;
  192.       when c=18 then p_row.col_s := v_cellval ;
  193.       when c=19 then p_row.col_t := v_cellval ;
  194.     end case;
  195.   end;
  196. begin
  197.   for c in 0..maxcol-1 loop
  198.     v_cellval := getString(ctx, row_idx, c) ;
  199.     fill_cell(v_cellval, c) ;
  200.   end loop;
  201. end ;

  202. function get_xls_table(p_data in blob, p_sheet int) RETURN xls_table PIPELINED
  203. is
  204. ctx poi_hssf.ctxHandle ;
  205. r int ;
  206. col_cnt pls_integer;
  207. sheet_cnt pls_integer ;
  208. vrow xls_row ;
  209. v_ret binary_integer;
  210. begin

  211.   ctx := poi_hssf.newcontext(p_data) ;
  212.   sheet_cnt := getSheets(ctx) ;

  213.   <<loop_sheet>>
  214.   for s in 0.. sheet_cnt-1 loop --多個excel sheet

  215.     if (p_sheet = -1 or p_sheet = s) then


  216.       v_ret := selectSheet(ctx, s) ;

  217.       <<loop_rows>>
  218.       for r in getFirstRowNum(ctx)..getLastRowNum(ctx) loop -- 抓每一行數據
  219.         vrow := null; -- 需先清空數據,可能不同sheet資料列不一樣多
  220.         vrow.sheet := s + 1 ;
  221.         
  222.         col_cnt := least(getColumns(ctx, r), c_max_cols) ;
  223.         vrow.row_idx := r +1;
  224.         get_xls_row_val(vrow, ctx, r, col_cnt ) ;
  225.         pipe row (vrow);
  226.       end loop loop_rows;
  227.     end if ;

  228.   end loop loop_sheet;

  229.   poi_hssf.closeContext(ctx) ;

  230.   exception
  231.     when NO_DATA_NEEDED then
  232.         poi_hssf.closeContext(ctx) ;
  233.     when excel_parsing_error then
  234.         poi_hssf.closeContext(ctx) ;
  235.         raise_application_error(-20013, 'open excel error'||sqlerrm);
  236. end get_xls_table;




  237.   PROCEDURE poitest(vfile varchar2)
  238.   as LANGUAGE JAVA NAME
  239.    'ExcelUtilWithHSSF.runtest(java.lang.String)';


  240. END poi_hssf;
  241. /

java code

点击(此处)折叠或打开

  1. create or replace and compile java source named "corp/poi/ExcelUtilWithHSSF" as
  2. package corp.poi;
  3. import oracle.CartridgeServices.ContextManager;
  4. import java.io.IOException;
  5. import org.apache.poi.hssf.usermodel.HSSFCell;
  6. import org.apache.poi.hssf.usermodel.HSSFCellStyle;
  7. import org.apache.poi.hssf.usermodel.HSSFRow;
  8. import org.apache.poi.hssf.usermodel.HSSFSheet;
  9. import org.apache.poi.hssf.usermodel.HSSFWorkbook;
  10. import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
  11. import org.apache.poi.hssf.usermodel.HSSFDateUtil;
  12. import org.apache.poi.hssf.util.HSSFColor;
  13. import java.sql.SQLException;
  14. import java.io.Writer;
  15. import java.io.StringWriter;
  16. import java.io.PrintWriter;
  17. import oracle.CartridgeServices.CountException ;
  18. import oracle.CartridgeServices.InvalidKeyException ;
  19. import java.util.Date;
  20. import java.text.SimpleDateFormat;

  21. /*********************
  22. oracle 10g可以使用poi version: poi-3.2-FINAL-20081019.jar / poi-bin-3.2-FINAL-20081019.zip
  23. **********************/

  24. public class ExcelReaderObj
  25. {
  26.    public HSSFWorkbook xls =null;
  27.    public HSSFSheet active_sheet =null;
  28.    public HSSFFormulaEvaluator evaluator=null;
  29. }

  30. public class ExcelUtilWithHSSF {
  31.   public static final int SUCCESS = 0;
  32.   public static final int FAILURE = -20013;

  33.   private static int SQLfailure(SQLException e, int[] errorCode, String[] errorMessage)
  34.   {
  35.       errorCode[0] = e.getErrorCode();
  36.       errorMessage[0] = e.getMessage();
  37.       return FAILURE;
  38.   }

  39.   private static String ExceptionString(Exception e)
  40.   {
  41.       Writer writer = new StringWriter();
  42.       PrintWriter printWriter = new PrintWriter(writer);
  43.       e.printStackTrace(printWriter);
  44.       return writer.toString();
  45.   }
  46.       
  47.   private static int Failure(Exception e, int[] errorCode, String[] errorMessage)
  48.   {
  49.       errorCode[0] = -20013 ;
  50.       errorMessage[0] = ExceptionString(e) ;
  51.       return FAILURE;
  52.   }
  53.   
  54.   public static int newcontext(java.io.InputStream data, int[] errorCode, String[] errorMessage)
  55.   {
  56.     errorCode[0] = SUCCESS ;
  57.     
  58.     try {
  59.         ExcelReaderObj xlsobj = new ExcelReaderObj();
  60.       //1.得到Excel工作簿象
  61.          xlsobj.xls = new org.apache.poi.hssf.usermodel.HSSFWorkbook(data);
  62.          xlsobj.evaluator = new HSSFFormulaEvaluator(xlsobj.xls);
  63.         return ContextManager.setContext(xlsobj) ;
  64.     } catch (Exception e) {
  65.       return Failure(e, errorCode, errorMessage);
  66.     }
  67.   }

  68.   public static int newcontext(oracle.sql.BLOB data, int[] errorCode, String[] errorMessage)
  69.   {
  70.     try {
  71.        return newcontext( data.getBinaryStream(), errorCode, errorMessage);
  72.     } catch (SQLException e) {
  73.       return SQLfailure(e, errorCode, errorMessage);
  74.     }
  75.   }

  76.   public static int newcontext(oracle.sql.BFILE data, int[] errorCode, String[] errorMessage)
  77.   {
  78.     try {
  79.         return newcontext( data.getBinaryStream(), errorCode, errorMessage);
  80.     } catch (SQLException e) {
  81.       return SQLfailure(e, errorCode, errorMessage);
  82.     }
  83.   }
  84.   

  85.   public static int closecontext(int ctx)
  86.   throws SQLException, CountException, InvalidKeyException
  87.   {
  88.     ExcelReaderObj xlsobj = (ExcelReaderObj) ContextManager.clearContext(ctx) ;
  89.     xlsobj = null;
  90.     return ContextManager.count ;
  91.   }
  92.   
  93.   
  94.   public static int getSheets(int ctx )
  95.   throws SQLException, CountException, InvalidKeyException
  96.   {
  97.     ExcelReaderObj xlsobj = (ExcelReaderObj) ContextManager.getContext(ctx) ;
  98.     return xlsobj.xls.getNumberOfSheets();
  99.   }
  100.   

  101.   public static int selectSheet(int ctx, int sheet)
  102.   throws SQLException, CountException, InvalidKeyException
  103.   {
  104.     ExcelReaderObj xlsobj = (ExcelReaderObj)ContextManager.getContext(ctx) ;
  105.     xlsobj.active_sheet = xlsobj.xls.getSheetAt(sheet);
  106.     return 0 ;
  107.   }
  108.   

  109.  public static int getFirstRowNum(int ctx)
  110.   throws SQLException, CountException, InvalidKeyException
  111.   {
  112.     ExcelReaderObj xlsobj = (ExcelReaderObj)ContextManager.getContext(ctx) ;
  113.     return xlsobj.active_sheet.getFirstRowNum();
  114.   }


  115.  public static int getLastRowNum(int ctx)
  116.   throws SQLException, CountException, InvalidKeyException
  117.   {
  118.     ExcelReaderObj xlsobj = (ExcelReaderObj)ContextManager.getContext(ctx) ;
  119.     return xlsobj.active_sheet.getLastRowNum();
  120.   }




  121.  public static int getColumns(int ctx, int prow)
  122.   throws SQLException, CountException, InvalidKeyException
  123.   {
  124.     ExcelReaderObj xlsobj = (ExcelReaderObj)ContextManager.getContext(ctx) ;
  125.     HSSFRow row = xlsobj.active_sheet.getRow(prow);
  126.     if (row == null) return 0;
  127.     
  128.     return row.getLastCellNum();
  129.   }
  130.   
  131.     private static String getOracleString(String str)
  132.     {
  133.         if (str.length()<1200) return str ; //不會超過4000 byte
  134.         
  135.         int len = ( str.length() > 4000 ) ? 4000 : str.length();
  136.         
  137.         byte v_bytes[] = str.substring(0, len).getBytes() ;
  138.         if (v_bytes.length <= 4000) return str;
  139.         
  140. // byte[] buf = new byte[4000];
  141. // System.arraycopy(v_bytes, 0, buf, 0, 4000);
  142.         return new String(v_bytes, 0, 4000) ;
  143.     }

  144.     private static String getDoubleString(double var1)
  145.     {
  146.        String s = Double.toString(var1) ;
  147.        if (s.endsWith(".0")) return s.substring(0, s.length()-2); //截斷 .0
  148.        return s;
  149.     }

  150.   public static String getCellValue(HSSFFormulaEvaluator evaluator, HSSFCell cell) {
  151.         switch (cell.getCellType()) {
  152.         case HSSFCell.CELL_TYPE_BOOLEAN:
  153.             return String.valueOf(cell.getBooleanCellValue());
  154.         case HSSFCell.CELL_TYPE_FORMULA:
  155.             return getCellValue(evaluator, evaluator.evaluateInCell(cell));
  156.         case HSSFCell.CELL_TYPE_NUMERIC:
  157.             if (HSSFDateUtil.isCellDateFormatted(cell)) {
  158.                 Date theDate = cell.getDateCellValue();
  159.                 return new SimpleDateFormat().format(theDate);
  160.             } else {
  161.                 return getDoubleString(cell.getNumericCellValue());
  162.             }
  163.         case HSSFCell.CELL_TYPE_STRING:
  164.             return cell.getRichStringCellValue().getString();
  165.         case HSSFCell.CELL_TYPE_BLANK:
  166.         case HSSFCell.CELL_TYPE_ERROR:
  167.         default:
  168.             return null;
  169.         }
  170.   }
  171.   

  172. /*****************************************
  173.     Oracle has a limit of 4000 bytes for VARCHAR2
  174. ******************************************/
  175.   public static String getString(int ctx, int row, int col)
  176.   throws CountException, InvalidKeyException
  177.   {
  178.     ExcelReaderObj xlsobj = (ExcelReaderObj)ContextManager.getContext(ctx) ;
  179.     HSSFRow row1 = xlsobj.active_sheet.getRow(row);
  180.     HSSFCell cell1 = row1.getCell(col);
  181.     if (cell1 ==null) return null;
  182.    
  183.     return getOracleString(getCellValue(xlsobj.evaluator, cell1));
  184.   }
  185. }
  186. /

1.
在oracle 10g的jre版本為1.4.2
poi版本最高可以使用poi-3.2-FINAL-20081019.jar,
如在oracle11g,12c中使用,可以使用較高的poi版本.

2.  歡迎大家使用,如發現有bug,請email告知.

阿飛
2015/09/08 整理

阅读(1318) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~