使用PL / SQL过程提取所有Oracle模式表

时间:2010-07-13 10:33:27

标签: plsql

我正在使用PL / SQL过程将特定模式的Oracle表提取为csv格式。我通过以下命令执行该过程:

exec dump_table_to_csv ( 'schema.tablename',  'directory',  'tablename.csv');

使用以下命令创建目录:

CREATE DIRECTORY <directory_name> AS '<operating_system_path>';

PL?SQL过程代码如下:

create or replace procedure dump_table_to_csv( p_tname in varchar2,
                                                   p_dir   in varchar2,
                                                   p_filename in varchar2 )
    is
        l_output        utl_file.file_type;
        l_theCursor     integer default dbms_sql.open_cursor;
        l_columnValue   varchar2(4000);
        l_status        integer;
        l_query         varchar2(1000)
                       default 'select * from ' || p_tname;
       l_colCnt        number := 0;
       l_separator     varchar2(1);
       l_descTbl       dbms_sql.desc_tab;
   begin
       l_output := utl_file.fopen( p_dir, p_filename, 'w', 32760);
       execute immediate 'alter session set nls_date_format=''dd-mon-yyyy hh24:mi:ss'' ';

       dbms_sql.parse(  l_theCursor,  l_query, dbms_sql.native );
       dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );

       for i in 1 .. l_colCnt loop
           utl_file.put( l_output, l_separator || '"' || l_descTbl(i).col_name || '"' );
           dbms_sql.define_column( l_theCursor, i, l_columnValue, 4000 );
           l_separator := ',';
       end loop;
       utl_file.new_line( l_output );

       l_status := dbms_sql.execute(l_theCursor);

       while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop
           l_separator := '';
           for i in 1 .. l_colCnt loop
               dbms_sql.column_value( l_theCursor, i, l_columnValue );
               utl_file.put( l_output, l_separator || l_columnValue );
               l_separator := ',';
           end loop;
           utl_file.new_line( l_output );
       end loop;
       dbms_sql.close_cursor(l_theCursor);
       utl_file.fclose( l_output );

       execute immediate 'alter session set nls_date_format=''dd-MON-yy'' ';
   exception
       when others then
           execute immediate 'alter session set nls_date_format=''dd-MON-yy'' ';
           raise;
   end;
   /

但是,当表格增加时,此过程需要很长时间。我的问题是如何修改代码,以便我可以处理列表模式表并将其放在一个文件中,然后该过程将处理文件中列出的所有表?如果这种方式不快或不可能,我可以用一种其他方式在一次运行中处理提取而不必为每个表执行过程?

3 个答案:

答案 0 :(得分:1)

  

我可以在一次运行中处理提取的其他方式,而无需为每个表执行过程吗?

您可以按如下方式自动运行当前程序:

begin
   for r in (select table_name from all_tables where owner = 'SCHEMA') loop
      dump_table_to_csv 
         ('schema.'||r.table_name, 'directory', r.table_name||'.csv');
   end loop;
end;

或者你可以重新编写要运行的程序:

exec dump_schema_to_csvs ('schema', 'directory')

即。把我的第一个例子中的FOR循环放在过程中。

但是,这些都不会比现有方法更快地运行。

答案 1 :(得分:0)

我猜你的性能打击来自这里的逐行处理......

       while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop
           l_separator := '';
           for i in 1 .. l_colCnt loop
               dbms_sql.column_value( l_theCursor, i, l_columnValue );
               utl_file.put( l_output, l_separator || l_columnValue );
               l_separator := ',';
           end loop;
           utl_file.new_line( l_output );
       end loop;

我鼓励你考虑让这个更加基于集合,它应该提高速度。快速搜索旧的互联网了small blog posting。作者在特定的sql语句中处理他所有的列分隔。

我理解您是否要保留此通用名称,以便您可以浏览所有表格。如果是这样的话,我会鼓励你考虑使用一些脚本而不仅仅是PLSQL。那里有几个例子......这是一个很好的起点:

http://amardeepsidhu.com/blog/2007/06/16/spool-to-a-xls-excel-file/

http://amardeepsidhu.com/blog/2007/06/26/shell-script-to-spool-a-no-of-tables-into-xls-files/

......那些都处理出口到excel,但你可以很容易地转换为csv。

最后,如果这只是一个偶然的事情,你可能想考虑抓住SQLDeveloper - 使用那个(免费)实用程序,你可以从一个简单的右键菜单导出任何表。

希望有帮助...

答案 2 :(得分:0)

看一下DBMS_JOB - 这将允许您提交每个表格提取作为后台作业,并行运行,直到您的计算机资源。

所以你可以从一个类似

的程序开始
begin
   for table_rec in (select table_name from user_tables) loop
      submit_dump_to_csv(
           schema_var||'.'||table_rec.table_name,
           'directory',
           table_rec.table_name||'.csv);
   end loop;
end;

其中submit_dump_to_csv包含您对dump_table_to_csv的调用并将其传递给DBMS_JOB。

您可能希望在表中记录已提交和已完成的作业,并可能使用DBMS_MAIL或DBMS_SMTP发送有关任务完成的电子邮件,因为作业将在服务器的后台执行。

这不会加速任何单个表提取,只允许并行提取不同的表。

为了加速单个提取,我会更改你的代码,以便不是使用方法4动态SQL提取所有列,然后在pl / sql中连接它们,而是使用ALL_TAB_COLUMNS构建一个返回的l_query版本单个连接字符串。

然后,您应该能够使用更简单的本机动态SQL语法来循环动态查询,为返回的每一行调用UTL_FILE。

或者。 。 。

如果您使用SQL * Plus,则可以执行类似

的操作
SET HEADING OFF PAGES 0 
SET COLSEP ","
SPOOL tablename.csv
SELECT * FROM tablename
SPOOL OFF

如果对tablename - &amp; tablename使用SQL Plus变量 - 这适用于任何表,并且您可以轻松编写由user_tables驱动的另一个脚本,以便为要提取的每个表调用此脚本(或者使用shell脚本,或者编写SQL Plus,用于假脱机输出文件,然后调用它假脱机的输出文件。)