Comments on: Read an Excel xlsx with PL/SQL Friends of Oracle and Java Wed, 08 Jul 2015 07:37:03 +0000 hourly 1 By: Anton Scheffer Wed, 03 Jun 2015 19:28:54 +0000 @Sagay. The max size of a varchar2 in a SQL-query is 4000 characters. If your excel contains larger strings you will get that error. I don’t handle that in purpose. If you do want to truncate those values, just change that line to t_one_cell.string_val := substr( t_strings( to_number( t_val ) ), 1, 4000 );

By: Sagay Wed, 03 Jun 2015 16:21:51 +0000 @Anton – Thanks for the package. It is parsing the Excel file as expected.

When I run the given query in SQL developer, after returning few 100 rows it hits “ORA-06502: PL/SQL: numeric or value error: character string buffer too small” at line 296 of the package.

Can you please help?

By: Nicolas Denis Thu, 23 Apr 2015 12:54:46 +0000 Here the way I proceed the Excel once loaded. I use this to rebuild the matrix to its original state using a single SQL query.
I dump the excel into a Global Temporary table for faster access, detect the “header” row (it may not be the first row) and rebuild my matrix with a query similar to:

SELECT MAX(DECODE(col_nr, 1, TRIM(string_val), NULL)) COL_A,
MAX(DECODE(col_nr, 2, TRIM(string_val), NULL)) COL_B
AND ROW_NR > nFirstRowID

That way, even if the package do not read empty cell – the output you get include the blank column with NULL.
Use “string_val”, “number_val” or “date_val” in the query depending with datatype you expect.

Hope this will help

By: Anton Scheffer Thu, 23 Apr 2015 10:31:08 +0000 In my opinion that doesn’t need to be fixed. The package reads values stored in a Excel file. If a column only contains a “column name”, that means there’s nothing stored in the other rows (for that column). And that means no output from this package. But if you know that the Excel contains a matrix, and you expect null values for empty cells, YOU can change the query to add those values, outer joining it to something for instance. But feel free to change to package yourself to fix it.

By: CUGAR Wed, 22 Apr 2015 10:03:28 +0000 Hi, this is great package, but I have one problem.

When column in excel file contains only column name (in first row) and rest of values in taht column contaions NULLs, package will read only column name and maybe one more row with Null value.
It will not read other NULL’s values from that column.

How can it be fixed?

By: Alberto Tue, 31 Mar 2015 17:57:32 +0000 Resolved, understood as change this directory, thank you.

By: Alberto Tue, 31 Mar 2015 17:33:40 +0000 Hello Anton,
you could be a little more specific when you say “DOC” in which directory server database references? as could change this path. thanks for this great contribution

By: Andrew Thu, 12 Mar 2015 14:50:59 +0000 I haven’t noticed any continued degradation after that fix but it may be possible the memory for the blobs are not released as well. Perhaps my files are not large enough to notice a difference.

There is this line which may have a similar effect since it is using a function to pass as a parameter.

t_nd := blob2node( get_file( p_xlsx, ‘xl/workbook.xml’ ) );

Perhaps setting the get_file() call to a local variable first will have an effect but that is just speculation right now. You may have to search through the code to find instances like that and try it out.

By: Martin Goblet Thu, 12 Mar 2015 14:35:55 +0000 Andrew

I didn’t see you post before :( Tried your solution, but the elapsed time still increases (a little bit less now) by each run. Could it be possible that the BLOB parameters memory is never reset (p_xlsx, p_blob, p_zipped_blob) ?


By: mago28 Thu, 12 Mar 2015 12:49:42 +0000 Thanks.

By: Andrew Thu, 12 Mar 2015 12:30:00 +0000 Martin,
I experienced the elapsed time increase with successive runs as well. There is a memory leak because a call to dbms_xmldom.getdocumentelement() is used as a parameter in a call to dbms_xmldom.newdocument(). The allocated memory is not released.
I made a fix for that by using a local variable t_ndoc for the getdocumentelement() call and then explicitly freeing the memory.

See my post on Oct 11, 2013.

-–return dbms_xmldom.makenode( dbms_xmldom.getdocumentelement( –dbms_xmldom.newdomdocument( xmltype( p_blob, nls_charset_id( ‘AL32UTF8′ ) ) ) ) );

t_ndoc := dbms_xmldom.newdomdocument( xmltype( p_blob, nls_charset_id( ‘AL32UTF8′ ) ) );
return dbms_xmldom.makenode( dbms_xmldom.getdocumentelement( t_ndoc ) );

By: Martin Goblet Thu, 12 Mar 2015 09:25:05 +0000 I do it this way :

SELECT MAX(DECODE(col_nr, 1, SUBSTR(string_val, 1, 10), ”)) cod_taric
, MAX(DECODE(col_nr, 1, SUBSTR(string_val, 12, 2), ”)) genre
, MAX(DECODE(col_nr, 2, date_val, ”)) dat_valid_from
, MAX(DECODE(col_nr, 3, string_val, ”)) utilisable
WHERE sheet_nr = 1 AND row_nr > 1 — Void description line
GROUP BY sheet_nr, row_nr
ORDER BY sheet_nr, row_nr;

By: Martin Goblet Thu, 12 Mar 2015 08:50:48 +0000 Hi Anton

Again, many thanks for this wonderful package (and for the as_zip too)

Just a little correction, because I got a error on a huge string : added a substr(…, 1, 4000) on 2 lines

IF t_t IN (‘str’, ‘inlineStr’, ‘e’) THEN
t_one_cell.cell_type := ‘S';
t_one_cell.string_val := SUBSTR(t_val, 1, 4000);
ELSIF t_t = ‘s’ THEN
t_one_cell.cell_type := ‘S';

t_one_cell.string_val := SUBSTR(t_strings(TO_NUMBER(t_val)), 1, 4000);

An other problem I noticed : when I run the procedure several times, it takes more time at each run. When I often run it on large xlsx files, I’ve to close my session and reopen it to start from scratch.

I guess that some memory is not freed up (DBMS_LOB.freetemporary, DBMS_SESSION.free_unused_user_memory, …) somewhere ?


By: Herbert Broich Thu, 12 Mar 2015 08:04:07 +0000 Thanks a lot!
This version works very well!

By: Anton Scheffer Tue, 10 Mar 2015 15:41:29 +0000 The latest version is linked in this blog.