create or replace package body extracts is
-----------------------------------------------------------------------------------------------
/* extracts.pkb - package body to dump data to files.
-----------------------------------------------------------------------------------------------
Procedure extract_table dumps one table into the requested directory on the dbms server.
All exceptions are thrown back to the caller.
The file created is as per spec:
- pipe-separated, including a trailing '|' after the last column
- IF NO DATA, NO FILE! This is as specified, but easily changed if required
- if split column is specified, one file is created for each value in that column
- if not split, the file is named as requested, or by default, <p_table>.txt
- if split, each file is named as above, prefixed with the split column value and '_'
- column headings can be requested via the p_headings argument
LIMITATIONS:
- only tables can be dumped; this hasn't been tested with views
- the table must have at least two columns, or the order by will fail
- if split, the p_split_by column must be alpha and contain no null values
-----------------------------------------------------------------------------------------------
*/
-----------------------------------------------------------------------------------------------
procedure extract_table( -- DUMP ONE TABLE
p_table cols.table_name%type -- table name
, p_dir varchar2 -- utl_dir location to put it
, p_file varchar2 := null -- file name required
, p_headings boolean := false -- column headings required
, p_split_by cols.column_name%type := null -- one file per value if not null
) is
cursor table_columns is -- column specs in table order
select column_name, data_type
from cols
where table_name = upper(p_table)
order by column_id;
b varchar2( 2000); -- break processing
d varchar2( 1000); -- declarations
f varchar2( 1000); -- output file
h varchar2( 3000); -- column headings
o varchar2( 3000); -- output line
p varchar2(13000); -- whole procedure
q varchar2( 1000); -- query
t varchar2( 2000); -- trailer processing
begin
d := 'declare'; -- build declarations
d := d || ' fh utl_file.file_type;'; -- file handle
d := d || ' fn varchar2(100);'; -- file name
d := d || ' nr number(9) := 0;'; -- number of records processed
d := d || ' sv varchar2(50) := ''.'';'; -- split_by column saved value
q := 'select * from ' || p_table; -- build main query
q := q || ' order by ';
if p_split_by is not null then
q := q || p_split_by || ', '; -- if split, split_by column must be first
end if;
q := q || '1, 2'; -- mprn, msn or mprn, primary supplier attribute
f := nvl(p_file, upper(p_table) || '.txt'); -- build constant part of filename
o := ''; -- build output line..
h := ''; -- ..and column headings
for c in table_columns loop
if length(o) > 0 then
o := o || ' || ';
end if;
if c.data_type = 'DATE' then
o := o || 'to_char(r.' || c.column_name || ', ''DD-MON-YYYY'')';
else
o := o || 'r.' || c.column_name;
end if;
o := o || ' || ''|''';
if p_headings then
h := h || c.column_name || '|';
end if;
end loop;
if p_headings then -- finish column headings
h := 'utl_file.put_line(fh, ''' || h || ''');';
end if;
if p_split_by is not null then -- build break handling, incl file open/close
b := ' if r.' || p_split_by || ' != sv then';
b := b || ' sv := r.' || p_split_by || ';';
b := b || ' if nr > 1 then';
b := b || ' utl_file.fclose(fh);';
b := b || ' end if;';
b := b || ' fn := sv || ''_'' || ''' || f || ''';';
b := b || ' fh := utl_file.fopen(''' || p_dir || ''', fn, ''w'', 10000);';
b := b || h;
b := b || ' end if;';
else -- just one file
b := ' if nr = 1 then';
b := b || ' fn := ''' || f || ''';';
b := b || ' fh := utl_file.fopen(''' || p_dir || ''', fn, ''w'', 10000);';
b := b || h;
b := b || ' end if;';
end if;
t := ' if nr > 0 then'; -- build trailer block
t := t || ' utl_file.fclose(fh);';
t := t || ' end if;';
p := d; -- assemble entire procedure
p := p || ' begin';
p := p || ' for r in (' || q || ') loop';
p := p || ' nr := nr + 1;';
p := p || b;
p := p || ' utl_file.put_line(fh, ' || o || ');';
p := p || ' end loop;';
p := p || t;
p := p || ' end;';
execute immediate p;
end extract_table;
-----------------------------------------------------------------------------------------------
end extracts;
/