oracle数据库中,用SQL Select直接訪問訪問存儲在blob中的excel數據

原文地址:oracle数据库中,用SQL Select直接訪問訪問存儲在blob中的excel數據 作者:gangjh

 在我的工作中,经常需要访问Excel数据或者导入到oracle数据库中

常用的做法是:
   在前端程序中是逐行访问,读取数据.
   在oracle后端也可以处理.还更加方便

我封装了一个通用的package utl_excel.用来用SQL直接查询.

範例1:  excel数据存放在exceldata的blob_data栏位
   select  *
    from  exceldata a,
    table( utl_excel.get_xls_table(blob_data) ) xx
    where a.name='MSOFFICE.EXCEL';

範例2:  直接读取http或者ftp上的excel文件,    utl_lob是另外一个通用package
  select  *
    from    table(
             utl_excel.get_xls_table(utl_lob.url2blob('http://192.168.1.11/data/test.xls')  ) )


原理:
  java使用 jxl.jar 訪問excel ,用pl/sql封装成package

oracle 封装代碼如下,

点击(此处)折叠或打开

  1. CREATE OR REPLACE PACKAGE utl_excel AS
  2. /****************************************************************************
  3.    Ver Date Author Description
  4.    --------- ---------- --------------- --------------------------------------------
  5.    1.0 2013-11-05 gangjh 1. 使用java jxl.jar 訪問blob的excel 2000數據.
  6.                                                返回table類型數據.
  7.                                                不支持xlsx,和ods格式
  8. *******************************************************************************/

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

  11.   type cell_val is record (
  12.   sheet int,
  13.   row_idx int,
  14.   col_idx int,
  15.   data celltype
  16.   ) ;
  17.   type xls_data is table of cell_val ;
  18.   c_max_cols constant pls_integer := 20;
  19.   type xls_row is record (
  20.     sheet int ,
  21.     row_idx int ,
  22.     col0 celltype,
  23.     col1 celltype,
  24.     col2 celltype,
  25.     col3 celltype,
  26.     col4 celltype,
  27.     col5 celltype,
  28.     col6 celltype,
  29.     col7 celltype,
  30.     col8 celltype,
  31.     col9 celltype,
  32.     col10 celltype,
  33.     col11 celltype,
  34.     col12 celltype,
  35.     col13 celltype,
  36.     col14 celltype,
  37.     col15 celltype,
  38.     col16 celltype,
  39.     col17 celltype,
  40.     col18 celltype,
  41.     col19 celltype
  42.   );
  43.   
  44.   type xls_table is table of xls_row ;
  45.  


  46. /****************************************
  47.  with xt as
  48. ( select a.id,a.name ,xx.*
  49.     from xmldata a,
  50.     table( utl_excel.get_xls_val(blob_temp) ) xx
  51.     where a.name='MSOFFICE.EXCEL'
  52. )

  53. select id,name,sheet,row_idx,
  54. max(decode(col_idx,0,data,'')) col0,
  55. max(decode(col_idx,1,data,'')) col1,
  56. max(decode(col_idx,2,data,'')) col2
  57. from xt
  58. group by id,name,sheet,row_idx;
  59. ************************/
  60.   
  61.   function get_xls_val(data in blob) RETURN xls_data PIPELINED ;


  62. /*********************************************
  63. ex1:
  64.   select a.id,xx.*,a.name
  65.     from xmldata a,
  66.     table( utl_excel.get_xls_table(blob_temp) ) xx
  67.     where a.name='MSOFFICE.EXCEL' and id=23 and sheet=4

  68. ex2:
  69. select * from table(utl_excel.get_xls_table(utl_lob.url2blob('ftp://172.17.2.43/pub/test001.xls')))
  70.     
  71. ************************************/

  72. -- p_sheet := -1 : select all sheet
  73.   function get_xls_table(p_data in blob, p_sheet int default -1 ) RETURN xls_table PIPELINED ;

  74.   function p_test(p_data in blob, p_sheet int, p_row int, p_col int) return clob ;


  75. END utl_excel;
  76. /
  77. CREATE OR REPLACE PACKAGE body utl_excel AS
  78. excel_parsing_error EXCEPTION;
  79.     pragma EXCEPTION_INIT(excel_parsing_error, -29532);
  80. /**************** java implement ****************************/
  81.   FUNCTION newContext(data IN blob) RETURN ctxHandle
  82.   as LANGUAGE JAVA NAME
  83.    'corp.excel.Excelobj.newcontext(oracle.sql.BLOB) return int';

  84.   PROCEDURE closeContext(ctx IN ctxHandle)
  85.   as LANGUAGE JAVA NAME
  86.    'corp.excel.Excelobj.closecontext(int)';

  87.   function getSheets(ctx IN ctxHandle) return binary_integer
  88.   as LANGUAGE JAVA NAME
  89.    'corp.excel.Excelobj.getSheets(int) return int';

  90.   function getRows(ctx IN ctxHandle, sheet binary_integer) return binary_integer
  91.   as LANGUAGE JAVA NAME
  92.    'corp.excel.Excelobj.getRows(int, int) return int';

  93.   function getColumns(ctx IN ctxHandle, sheet binary_integer) return binary_integer
  94.   as LANGUAGE JAVA NAME
  95.    'corp.excel.Excelobj.getColumns(int, int) return int';

  96.  -- for cell data length >4000 byte
  97.   procedure getClob(ctx IN ctxHandle, sheet binary_integer, p_row in binary_integer, p_col in binary_integer, p_clob in out nocopy clob)
  98.   as LANGUAGE JAVA NAME
  99.    'corp.excel.Excelobj.getClob(int, int, int, int, oracle.sql.CLOB[])';

  100. -- Oracle has a limit of 4000 bytes for a VARCHAR2, >4000 will by trim
  101.   FUNCTION getString(ctx IN ctxHandle, sheet binary_integer, p_row in binary_integer, p_col in binary_integer) RETURN varchar2
  102.   as LANGUAGE JAVA NAME
  103.    'corp.excel.Excelobj.getString(int, int, int, int) return java.lang.String';

  104.   function getSheetCount(ctx IN ctxHandle) return binary_integer
  105.   as LANGUAGE JAVA NAME
  106.    'corp.excel.Excelobj.getSheetCount(int) return int';

  107. /*********************************************/

  108. function get_xls_val(data in blob) RETURN xls_data PIPELINED
  109. is
  110. ctx utl_excel.ctxHandle ;
  111. r int ;
  112. sheet_cnt pls_integer ;
  113. row_cnt pls_integer;
  114. col_cnt pls_integer;
  115. cell cell_val ;
  116. begin
  117.   ctx := newcontext(data) ;
  118.   
  119.   sheet_cnt := getSheets(ctx) ;
  120.   for s in 0.. sheet_cnt-1 loop --多個excel sheet
  121.     cell.sheet := s;
  122.     row_cnt := getrows(ctx, s) ;
  123.     col_cnt := getColumns(ctx, s) ;
  124.     for r in 0..row_cnt-1 loop --sheet中抓每一行
  125.       cell.row_idx :=r ;
  126.       for c in 0..col_cnt-1 loop --每行的每一列
  127.         cell.col_idx := c;
  128.         cell.data := getString(ctx,s, r,c) ;
  129.         pipe row (cell);
  130.       end loop;
  131.     end loop;
  132.   end loop;
  133.   closeContext(ctx) ;
  134.   return;
  135.   
  136.  exception
  137.     when NO_DATA_NEEDED then
  138.         utl_excel.closeContext(ctx) ;
  139. end get_xls_val;


  140. procedure get_xls_row_val(p_row in out xls_row, ctx ctxHandle, sheet pls_integer,row_idx pls_integer, maxcol pls_integer) is
  141.   v_cellval celltype ;
  142. begin
  143.   for c in 0..maxcol-1 loop
  144.     v_cellval := getString(ctx, sheet, row_idx, c) ;
  145.     case
  146.       when c=0 then p_row.col0 := v_cellval ;
  147.       when c=1 then p_row.col1 := v_cellval ;
  148.       when c=2 then p_row.col2 := v_cellval ;
  149.       when c=3 then p_row.col3 := v_cellval ;
  150.       when c=4 then p_row.col4 := v_cellval ;
  151.       when c=5 then p_row.col5 := v_cellval ;
  152.       when c=6 then p_row.col6 := v_cellval ;
  153.       when c=7 then p_row.col7 := v_cellval ;
  154.       when c=8 then p_row.col8 := v_cellval ;
  155.       when c=9 then p_row.col9 := v_cellval ;
  156.       when c=10 then p_row.col10 := v_cellval ;
  157.       when c=11 then p_row.col11 := v_cellval ;
  158.       when c=12 then p_row.col12 := v_cellval ;
  159.       when c=13 then p_row.col13 := v_cellval ;
  160.       when c=14 then p_row.col14 := v_cellval ;
  161.       when c=15 then p_row.col15 := v_cellval ;
  162.       when c=16 then p_row.col16 := v_cellval ;
  163.       when c=17 then p_row.col17 := v_cellval ;
  164.       when c=18 then p_row.col18 := v_cellval ;
  165.       when c=19 then p_row.col19 := v_cellval ;
  166.     end case;
  167.   end loop;
  168. end ;




  169. function get_xls_table(p_data in blob, p_sheet int) RETURN xls_table PIPELINED
  170. is
  171. ctx utl_excel.ctxHandle ;
  172. r int ;
  173. row_cnt pls_integer;
  174. col_cnt pls_integer;
  175. sheet_cnt pls_integer ;
  176. vrow xls_row ;
  177. begin
  178.   
  179.   ctx := utl_excel.newcontext(p_data) ;
  180.   sheet_cnt := getSheets(ctx) ;
  181.   
  182.   <<loop_sheet>>
  183.   for s in 0.. sheet_cnt-1 loop --多個excel sheet
  184.     --?
  185.     if (p_sheet = -1 or p_sheet = s) then
  186.     

  187.       vrow.sheet := s ;
  188.       
  189.       row_cnt := getrows(ctx, s) ;
  190.       
  191.       col_cnt := getColumns(ctx, s) ;
  192.       if col_cnt >c_max_cols then
  193.         col_cnt := c_max_cols ;
  194.       end if ;
  195.       
  196.       <<loop_rows>>
  197.       for r in 0..row_cnt-1 loop --抓每一行數據
  198.         vrow.row_idx := r;
  199.         get_xls_row_val(vrow, ctx, s, r, col_cnt ) ;
  200.         pipe row (vrow);
  201.       end loop loop_rows;
  202.     end if ;
  203.     
  204.   end loop loop_sheet;

  205.   utl_excel.closeContext(ctx) ;
  206.   
  207.   exception
  208.     when NO_DATA_NEEDED then
  209.         utl_excel.closeContext(ctx) ;
  210.     when excel_parsing_error then
  211.         utl_excel.closeContext(ctx) ;
  212.         raise_application_error(-20013, 'open excel error');
  213. end get_xls_table;


  214. function p_test(p_data in blob, p_sheet int, p_row int, p_col int) return clob is
  215.   ctx utl_excel.ctxHandle ;
  216.   cc clob ;
  217. begin
  218.   dbms_lob.createtemporary(cc, true, dbms_lob.call);
  219.   ctx := newContext(p_data) ;
  220.   getClob(ctx, p_sheet, p_row, p_col, cc) ;
  221.   closeContext(ctx) ;
  222.   return cc ;
  223. end ;



  224. END utl_excel;
  225. /



java 代碼 Excelobj.java

点击(此处)折叠或打开

  1. create or replace and compile java source named "corp/excel/Excelobj" as
  2. package corp.excel;
  3. //import sqlj.runtime.ref.DefaultContext;
  4. //import sqlj.runtime.ConnectionContext;
  5. import oracle.CartridgeServices.ContextManager;
  6. import jxl.Workbook;
  7. import jxl.Sheet;
  8. import jxl.Cell;

  9. import java.io.IOException ;
  10. import java.sql.SQLException;
  11. import oracle.CartridgeServices.CountException ;
  12. import jxl.read.biff.BiffException ;
  13. import oracle.CartridgeServices.InvalidKeyException ;

  14. /**************
  15. 2014-02-14 重新封裝jxl.Workbook
  16. ***************/
  17. public class Excelobj
  18. {
  19.   public static int newcontext(oracle.sql.BLOB data)
  20.   throws SQLException, CountException, IOException, BiffException
  21.   {
  22.     Workbook xls = Workbook.getWorkbook( data.getBinaryStream() ) ;
  23.     return ContextManager.setContext(xls) ;
  24.   }

  25.   public static int newcontext(oracle.sql.BFILE data)
  26.   throws SQLException, CountException ,IOException, BiffException
  27.   {
  28.     int r ;
  29.     Workbook xls = Workbook.getWorkbook( data.getBinaryStream() ) ;
  30.     return ContextManager.setContext(xls) ;
  31.   }


  32.  public static int getSheets(int ctx )
  33.   throws SQLException, CountException, InvalidKeyException
  34.   {
  35.     Workbook xls = (Workbook) ContextManager.getContext(ctx) ;
  36.     return xls.getNumberOfSheets();
  37.   }



  38.  public static int getRows(int ctx, int sheet)
  39.   throws SQLException, CountException, InvalidKeyException
  40.   {
  41.     Workbook xls = (Workbook)ContextManager.getContext(ctx) ;
  42.     Sheet xls_sheet = xls.getSheet(sheet) ;
  43.     return xls_sheet.getRows();
  44.   }

  45.  public static int getColumns(int ctx, int sheet)
  46.   throws SQLException, CountException, InvalidKeyException
  47.   {
  48.     Workbook xls = (Workbook)ContextManager.getContext(ctx) ;
  49.     Sheet xls_sheet = xls.getSheet(sheet);
  50.     return xls_sheet.getColumns() ;
  51.   }


  52.   public static void getClob(int ctx, int sheet, int row, int col, oracle.sql.CLOB[] outval)
  53.   throws SQLException, CountException, InvalidKeyException
  54.   {
  55.     Workbook xls = (Workbook)ContextManager.getContext(ctx) ;
  56.     Sheet xls_sheet = xls.getSheet(sheet);
  57.     Cell vcell = xls_sheet.getCell(col,row) ;
  58.     outval[0].setString(1, vcell.getContents()) ;
  59.   }
  60.   
  61. /*****************************************
  62.     Oracle has a limit of 4000 bytes for VARCHAR2
  63. ******************************************/
  64.   public static String getString(int ctx, int sheet, int row, int col)
  65.   throws SQLException, CountException, InvalidKeyException
  66.   {
  67.     Workbook xls = (Workbook)ContextManager.getContext(ctx) ;
  68.     Sheet xls_sheet = xls.getSheet(sheet);
  69.     
  70.     String v_str = xls_sheet.getCell(col,row).getContents() ;
  71.     
  72.     byte[] v_bytes = v_str.getBytes() ;
  73.     
  74.     if (v_bytes.length <= 4000) {
  75.         return v_str;
  76.     } else {
  77.         byte[] buf = new byte[4000];
  78.         System.arraycopy(v_bytes, 0, buf, 0, 4000);
  79.         return new String(buf) ;
  80.     }
  81.   }
  82.   


  83.   public static int getcnt(int ctx)
  84.   throws SQLException, CountException, InvalidKeyException
  85.   {
  86.     return ContextManager.count ;
  87.   }


  88.   public static int closecontext(int ctx)
  89.   throws SQLException, CountException, InvalidKeyException
  90.   {
  91.     Workbook xls = (Workbook) ContextManager.clearContext(ctx) ;
  92.     xls.close() ;
  93.     xls = null;

  94.     return ContextManager.count ;
  95.   }
  96. }
  97. /



注意事项:
  1. oracle 10g的jdk是1.4
  jxl版本不能用最新的.  我用的是jxl -2 .6 .jar

2.  装入jar请用 loadjava
  loadjava -u user/pass  -v -f jxl-2.6.jar

3. pb装入excel到blob请用updateblob

4. Excel 2007可以用as_xlsx_read读取,我的思路参考as_xlsx_read后些出来的
  http://technology.amis.nl/2013/01/19/read-a-excel-xlsx-with-plsql/
  select * from table ( as_read_xlsx . read ( as_read_xlsx . file2blob ( 'DOC' , 'Book1.xlsx' ) ) );


欢迎和大家一起交流oracle技术.

2014/02/24修改
當長度>4000時截斷
                                                   阿飞
                                              2014/02/21
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值