我看到了 Anton Scheffer 开发的一个叫做 as_xlsx
的包,使用 PL/SQL 创建 Excel 文件,它解决了我的问题。我还修改了一下,加入了工作表名称并允许将 SYS_REFCURSOR
作为参数,而不是我之前发布的帖子 (返回显式游标的 SQL 语句) 中所要求的 VARCHAR2
。
我在包规范中添加了该过程重载:
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
if p_sheetname is not null then
new_sheet(p_sheetname);
else
new_sheet;
end if;
t_d := DBMS_SQL.TO_CURSOR_NUMBER(p_cur);
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;
case
when t_desc_tab( c ).col_type in ( 2, 100, 101 )
then
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_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_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() );
loop
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_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_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_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_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_d )
then
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
, p_sheetname => i.payroll_name);
as_xlsx.freeze_pane( 1,1 );
end loop;
g_stage := 'Create the File';
as_xlsx.save( l_directory , l_filename||'.xlsx');
END EMP_ROSTER_REPORT;
希望这能帮助到某些人!:)
.csv
测试。但主要还是希望使用.xlsx
,因为业务用户更喜欢这种格式。 - Migs Isip.xls
文件大小为25.9 MB,.csv
文件大小为25.4 MB。我还没有研究过使用分隔符的文本。我会看看是否能够创建一个程序来处理它。 - Migs Isip