关于我之前的问题返回显式游标的 SQL 语句, 我能够使用
(.xls)
和 DBMS_SQL
生成 Excel UTL_FILE
文件并传递 SYS_REFCURSOR
(代码位于上一个问题中)。
然而,我遇到的一个挑战是生成的文件超过 25 MB。
我将通过电子邮件将此信息传输给企业用户,这肯定会填满他们的邮箱大小。
当我使用 xlsx
手动提取到 SQL Developer
时,它只会生成大约 4 MB 的数据。
为了解决这个问题,是否可以通过
PL/SQL
执行以下操作?
.xlsx
)生成文件来压缩大小.xls
文件我还在 SO 中回顾了类似的帖子,例如 在 Oracle 中使用 UTL_FILE 包在 ExcelSheet 中写入, 但正如答案所说,它需要使用Java。所以它不适用于我。 另一篇文章从 Oracle 数据库创建 Excel 电子表格,也使用
xls
。所以它也不适用。
有什么想法吗?
Oracle版本:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
PL/SQL Release 11.2.0.4.0 - Production
"CORE 11.2.0.4.0 Production"
TNS for Solaris: Version 11.2.0.4.0 - Production
NLSRTL Version 11.2.0.4.0 - Production
我见过 Anton Scheffer 开发的一个名为
as_xlsx
的包,使用 PL/SQL 创建 Excel 文件,它解决了我的问题。
我还对其进行了一些修改,以放入工作表名称并允许 SYS_REFCURSOR
作为参数,而不是按照我上一篇文章中的要求使用 VARCHAR2
(返回显式游标的 SQL 语句)。
我在过程重载的包规范中添加了这个:
procedure query2sheet
( p_cur IN OUT SYS_REFCURSOR
, p_column_headers boolean := true
, p_directory varchar2 := null
, p_filename varchar2 := null
, p_sheet pls_integer := null
, p_sheetname varchar2 := null
);
我在程序重载的包体中添加了这个(注意:行注释是我修改的行):
procedure query2sheet
( p_cur IN OUT SYS_REFCURSOR
, p_column_headers boolean := true
, p_directory varchar2 := null
, p_filename varchar2 := null
, p_sheet pls_integer := null
, p_sheetname varchar2 := null
)
is
t_sheet pls_integer;
t_c integer;
t_col_cnt integer;
t_desc_tab2 dbms_sql.desc_tab2;
t_desc_tab dbms_sql.desc_tab;
d_tab dbms_sql.date_table;
n_tab dbms_sql.number_table;
v_tab dbms_sql.varchar2_table;
t_bulk_size pls_integer := 200;
t_r integer;
t_cur_row pls_integer;
t_d number;
begin
-- Changed
if p_sheetname is not null then
new_sheet(p_sheetname);
else
new_sheet;
end if;
-- End of Change
--t_c := dbms_sql.open_cursor;
--dbms_sql.parse( t_c, p_sql, dbms_sql.native );
t_d := DBMS_SQL.TO_CURSOR_NUMBER(p_cur);
--dbms_sql.describe_columns2( t_c, t_col_cnt, t_desc_tab );
dbms_sql.describe_columns( t_d, t_col_cnt, t_desc_tab );
for c in 1 .. t_col_cnt
loop
if p_column_headers
then
cell( c, 1, t_desc_tab( c ).col_name, p_sheet => t_sheet );
end if;
--dbms_output.put_line( t_desc_tab( c ).col_name || ' ' || t_desc_tab( c ).col_type );
case
when t_desc_tab( c ).col_type in ( 2, 100, 101 )
then
--dbms_sql.define_array( t_c, c, n_tab, t_bulk_size, 1 );
dbms_sql.define_array( t_d, c, n_tab, t_bulk_size, 1 );
when t_desc_tab( c ).col_type in ( 12, 178, 179, 180, 181 , 231 )
then
--dbms_sql.define_array( t_c, c, d_tab, t_bulk_size, 1 );
dbms_sql.define_array( t_d, c, d_tab, t_bulk_size, 1 );
when t_desc_tab( c ).col_type in ( 1, 8, 9, 96, 112 )
then
--dbms_sql.define_array( t_c, c, v_tab, t_bulk_size, 1 );
dbms_sql.define_array( t_d, c, v_tab, t_bulk_size, 1 );
else
null;
end case;
end loop;
--
t_cur_row := case when p_column_headers then 2 else 1 end;
t_sheet := nvl( p_sheet, workbook.sheets.count() );
--
--t_r := dbms_sql.execute( t_c );
loop
--t_r := dbms_sql.fetch_rows( t_c );
t_r := dbms_sql.fetch_rows( t_d );
if t_r > 0
then
for c in 1 .. t_col_cnt
loop
case
when t_desc_tab( c ).col_type in ( 2, 100, 101 )
then
--dbms_sql.column_value( t_c, c, n_tab );
dbms_sql.column_value( t_d, c, n_tab );
for i in 0 .. t_r - 1
loop
if n_tab( i + n_tab.first() ) is not null
then
cell( c, t_cur_row + i, n_tab( i + n_tab.first() ), p_sheet => t_sheet );
end if;
end loop;
n_tab.delete;
when t_desc_tab( c ).col_type in ( 12, 178, 179, 180, 181 , 231 )
then
--dbms_sql.column_value( t_c, c, d_tab );
dbms_sql.column_value( t_d, c, d_tab );
for i in 0 .. t_r - 1
loop
if d_tab( i + d_tab.first() ) is not null
then
cell( c, t_cur_row + i, d_tab( i + d_tab.first() ), p_sheet => t_sheet );
end if;
end loop;
d_tab.delete;
when t_desc_tab( c ).col_type in ( 1, 8, 9, 96, 112 )
then
--dbms_sql.column_value( t_c, c, v_tab );
dbms_sql.column_value( t_d, c, v_tab );
for i in 0 .. t_r - 1
loop
if v_tab( i + v_tab.first() ) is not null
then
cell( c, t_cur_row + i, v_tab( i + v_tab.first() ), p_sheet => t_sheet );
end if;
end loop;
v_tab.delete;
else
null;
end case;
end loop;
end if;
exit when t_r != t_bulk_size;
t_cur_row := t_cur_row + t_r;
end loop;
--dbms_sql.close_cursor( t_c );
dbms_sql.close_cursor( t_d );
if ( p_directory is not null and p_filename is not null )
then
save( p_directory, p_filename );
end if;
exception
when others
then
--if dbms_sql.is_open( t_c )
if dbms_sql.is_open( t_d )
then
--dbms_sql.close_cursor( t_c );
dbms_sql.close_cursor( t_d );
end if;
end query2sheet;
这是我的并发请求中创建文件的示例块:
Procedure EMP_ROSTER_REPORT (p_empno per_all_people_f.employee_number%type
, p_bg_id per_business_groups.business_group_id%type
, p_email_add per_all_people_f.email_address%type)
is
l_fh UTL_FILE.FILE_TYPE;
l_directory VARCHAR2(30) := 'EXT_TAB_DATA';
l_filename VARCHAR2(100);
emp_cur SYS_REFCURSOR;
l_message varchar2(100);
g_stage varchar2(100);
g_zipped_blob blob;
cursor p_payroll_cur is
select payroll_id
, payroll_name
, business_group_id
from pay_all_payrolls_f
where business_group_id = p_bg_id;
BEGIN
-----------------------------------
g_stage := 'setting the filename';
-----------------------------------
l_filename := 'EMPLOYEE_ROSTER_REPORT_'||TO_CHAR(SYSDATE, 'DD-MON-YYYY-HHMISS');
------------------------------------------
g_stage := 'Assigning Emp SysRefCursor';
------------------------------------------
for i in p_payroll_cur loop
OPEN emp_cur FOR
SELECT 'extra long query here with parameters'
from table_a
where payroll_id = i.payroll_id;
----------------------------------------------------------
g_stage := 'open Employee Cursor and write into the File';
----------------------------------------------------------
as_xlsx.query2sheet( p_cur => emp_cur -- Uses Sys_RefCursor Instead of Dynamic SQL (Varchar2)
, p_sheetname => i.payroll_name); -- This is where we assign the Sheet Names
as_xlsx.freeze_pane( 1,1 ); -- Freeze the topmost and rightmost pane in the Excel Sheet
end loop;
------------------------------
g_stage := 'Create the File';
------------------------------
as_xlsx.save( l_directory , l_filename||'.xlsx');
END EMP_ROSTER_REPORT;
希望这对某人有帮助! :)
Oracle 数据库中不支持 xls
或
xlsx
文件。您可以创建 CSV(逗号分隔)文件,然后使用自定义
java 存储过程(使用 java.util.zip
UTL_COMPRESS
的 PL/SQL 过程将其压缩为 zip 文件.
ref cursor
以及报告内容的程序,然后设置一些使用数据生成 PDF 或 XLSX 并发送的服务。如果您无法在 DB 外部执行此操作,您仍然可以在 Oracle 内部使用 Java。您可以创建将创建 XLSX 的 Java 过程。
这里是Java创建Excel文件的示例。但是创建复杂的 Java 过程并不是最好的解决方案,可能需要您在数据库服务器上安装一些 jar,因此我将创建返回 ref cursor
的过程,其中包含数据和创建文件并将其发送到数据库之外的小程序。
oracle ebs并发程序xlsx