以前の質問 明示カーソルのSQLステートメントを返す に関連して、(.xls)
およびDBMS_SQL
を使用してExcel UTL_FILE
ファイルを生成し、 SYS_REFCURSOR
(コードは前の質問にあります)。しかし、私が直面している課題の1つは、生成されたファイルが25 MBを超えることです。これをビジネスユーザーに電子メールで送信し、メールボックスのサイズが確実にいっぱいになるようにします。 SQL Developer
を使用してxlsx
に手動で抽出すると、約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
ファイルのサポートはnoです。
できることは、CSV(カンマ区切り)ファイルを作成してから、カスタムの Javaストアドプロシージャ を使用してZipファイルに圧縮することです -[Java.util.Zip
を使用します。 UTL_COMPRESS
を使用するPL/SQLプロシージャ。
XLSXファイルを作成してビジネスユーザーに送信する必要がある場合は、DB外の一部のサービスの仕事のように思えます。レポートの内容でref cursor
を返すプロシージャを準備し、データを消費するサービスをセットアップしてPDFまたはXLSXを生成して送信する必要があります。
DBの外で実行できない場合でも、Oracle内でJavaを使用できます。 XLSXを作成するJavaプロシージャを作成できます。 ここ は、Excelファイルを作成するJavaの例です。しかし、複雑なJavaプロシージャを作成することは最良の解決策ではなく、おそらくDBサーバーにいくつかのjarをインストールする必要があるので、ファイルを作成して送信するデータと小さなプログラムでref cursor
を返すプロシージャを作成しますDBの外部。