Re: exporting a table to a flat file in .csv format
Date: Tue, 26 Aug 2003 17:13:17 -0700
Message-ID: <wIS2b.65830$kP.46061_at_fed1read03>
Jon wrote:
[Quoted] [Quoted] > I am trying to dump data from a table to a flat file in .csv format. I have > read documentation for sqlplus utility but I have not seen any information > about this apart from defining specific format for columns. Do you know if > this is posible from sqplus?
For LARGE tables it's faster to use Perl's DBI/DBD interface; and not SQL*Plus
The author of the code below is Jared Still;
who also is the author of the book:
Perl for the Oracle DBA.
#!/home/oracle/perl/bin/perl
=head1 dunldr
unload data from an oracle database
use 'dunldr -help' for help on usage
jared still
10/24/2001
=cut
use warnings;
use FileHandle;
use DBI;
use strict;
use File::Path;
use IO::File;
use Data::Dumper;
use Getopt::Long;
our %optctl = ();
our %bincol = ();
our %hexcols = ();
unless (
Getopt::Long::GetOptions( \%optctl,
"database=s",
"username=s",
"password=s",
"owner=s",
"directory=s",
"dateformat=s",
"header!",
"schemadump!",
"longlen=i",
"rowlimit=i",
"table=s_at_",
"bincol=s" => \%bincol,
"sysdba!",
"sysoper!",
"z","h","help"
)
) { Usage(1); }
for my $table ( keys %bincol ) {
my _at_bincols = split(/\,/,$bincol{$table});
$hexcols{uc($table)} = \_at_bincols;
}
#print Dumper(\%optctl);
#print Dumper(\%hexcols);
#for my $hexdumpcol ( _at_{$hexcols{XML_DATA}} ) {
#print "hexdumpcol: $hexdumpcol\n";
#}
#exit;
our($db, $username, $password, $connectionMode);
$connectionMode = 0;
if ( $optctl{sysoper} ) { $connectionMode = 4 }
if ( $optctl{sysdba} ) { $connectionMode = 2 }
Usage(1) unless $optctl{database};
Usage(1) unless $optctl{username};
Usage(1) unless $optctl{password};
Usage(1) unless $optctl{owner};
$optctl{longlen} = 65535 unless $optctl{longlen};
if ( $optctl{h} || $optctl{z} || $optctl{help} ) {
Usage(0);
}
if ( $optctl{schemadump} ) {
$optctl{table} = ['SCHEMADUMP'];
} else {
Usage(1) unless $optctl{table}; }
# default hdr to off
$optctl{header} ||= 0;
#if ( $optctl{bincol} ) {
#}
$username=$optctl{username};
$password = $optctl{password};
$db = $optctl{database};
# create the working directory
unless ( $optctl{directory} ) {
$optctl{directory} = qq{$optctl{owner}.dump};
}
# create directory path if it doesn't exist -d $optctl{directory} || File::Path::mkpath([$optctl{directory}]);
our $dbh = DBI->connect(
'dbi:Oracle:' . $db,
$username, $password,
{
RaiseError => 1,
AutoCommit => 0,
ora_session_mode => $connectionMode
}
);
die "Connect to $db failed \n" unless $dbh;
$dbh->{LongReadLen} = $optctl{longlen};
# set Oracle NLS date format
if ( $optctl{dateformat} ) {
$dbh->do(qq{alter session set nls_date_format
= '$optctl{dateformat}'} );
}
my $tableHash = new Tables($dbh, \%optctl);
#print "tables: ", join(':', keys %{$tableHash}), "\n"; #for my $table ( keys %{$tableHash} ){
#print "TABLE: $table FILE: $tableHash->{$table}\n"; #}
# print console info immediately
autoflush STDOUT 1;
my $sth;
# take a dump
for my $table ( keys %{$tableHash} ){
print "Table: $table\n";
my $sql = qq{select * from $optctl{owner}\.$table};
if ( $optctl{rowlimit}){
$sql .= qq{ where rownum <= $optctl{rowlimit}};
}
$sth = $dbh->prepare($sql);
my _at_columns = @{$sth->{NAME_uc}};
my %colOrder = ();
for my $el ( 0 ..$#columns ) {
$colOrder{$columns[$el]} = $el;
}
my $dumpFile = $optctl{directory} . '/' . $tableHash->{$table};
open(DUMP, "+> $dumpFile") || die "could not create file $dumpFile
- $!\n";
if ( $optctl{header} ) {
print DUMP join(',',_at_columns),"\n";
}
$sth->execute;
# create the ctl and par files
Tables->createCtl(
TABLE => $table,
COLUMNS => \_at_columns,
DUMPFILE => $tableHash->{$table},
DIRECTORY => $optctl{directory},
SCHEMA => $optctl{owner},
HEXCOLS => \_at_{$hexcols{$table}},
COLORDER => \%colOrder
);
# turn warnings off here so that warnings are not
# reported for null columns when printed
# comment it out to see what I mean
no warnings;
while ( my $ary = $sth->fetchrow_arrayref ) {
# change column to hex if specified as binary via -bincol
arg
if ( exists $hexcols{$table} ) {
for my $hexdumpcol ( _at_{$hexcols{$table}} ) {
$ary->[$colOrder{uc($hexdumpcol)}] =
uc(unpack("H*",$ary->[$colOrder{uc($hexdumpcol)}]));
}
}
print DUMP q{"} . join(q{","},_at_{$ary}) . qq{"\n};
#print "ROW: " . q{'} . join(q{','},_at_{$ary}) . qq{'\n};
}
use warnings;
close DUMP;
}
$sth->finish;
$dbh->disconnect;
sub Usage {
my ($exitCode) = _at__;
print q{
dunldr - data unloader for Oracle
usage:
dunldr -database <database> -username <userid> -password <password> \
-directory <data unload directory> \
-header|noheader \
-owner <schema owner> \
-table <table1,table2,table3,...)
-database database name
-username user to login as
-password password for login user
-owner owner of tables to dump
-directory directory to unload data into
will default to <owner>.dump
-dateformat Oracle NLS date format - optional
-header|noheader should first line include column names?
-table table to dump. may be repeated as many
times as necessary.
-schemadump dump entire schema of <owner>
will ignore -table settings
-rowlimit limit number of rows returned
-longlen if longs are in the table, set this
to the maximum length you want.
defaults to 65535
-bincol use to specify columns that should be dumped
in hex format. columns with binary data tend
to cause problems in text dumps.
e.g. -bincol <table_name>=<column_name,column_name,...>
dunldr -database orcl -username system -password manager \
-owner scott -directory scott.tables \
-header \
-table emp \
-table dept \
-table sales
dunldr -database orcl -username system -password manager \
-owner scott \
-dateformat 'mm/dd/yyyy' \
-header \
-schemadump \
-bincol xml_data=payload,header,authorization \
-bincol app_notes=text
};
exit $exitCode ? $exitCode : 0; }
package Tables;
sub new {
my $pkg = shift;
my $class = ref($pkg) || $pkg;
my ( $dbh, $optionHash ) = _at__;
my $tableHash;
if ( grep(/^SCHEMADUMP$/, _at_{$optionHash->{table}} ) ) {
# get all tables of owner
my $sql = q{
select table_name
from all_tables
where owner = ?
};
my $sth = $dbh->prepare($sql);
$sth->execute(uc($optionHash->{owner}));
my _at_tableArray;
while( my $ary = $sth->fetchrow_arrayref ) {
push(_at_tableArray, $ary->[0]);
}
$tableHash = setTables(\_at_tableArray);
} else {
$tableHash = setTables(\_at_{$optionHash->{table}});
}
bless $tableHash, $class;
return $tableHash;
}
=head1 setTables
make a neat hash of the form TABLE_NAME => 'table_name.dump' all table names upper case, all file names lower case for dump file names - Perl is awesome
=cut
sub setTables {
my ($tableArray) = shift;
my %tables = map(
split(/:/, $_),
map(
$_.':'.lc($_).'.txt',
split(
/:/,
uc(join(':',_at_{$tableArray}))
)
)
);
# uncomment these lines to see it
#use Data::Dumper;
#print Dumper(\%tables);
#exit;
my $hashRef = \%tables;
return $hashRef;
}
sub createCtl {
my($self,%args) = _at__;
my _at_columns = @{$args{COLUMNS}};
my %colOrder = %{$args{COLORDER}};
if ( $args{HEXCOLS} ) {
for my $hexdumpcol ( _at_{$args{HEXCOLS}} ) {
$columns[$colOrder{uc($hexdumpcol)}] =
$columns[$colOrder{uc($hexdumpcol)}] .
qq{ "hex_to_raw(:$columns[$colOrder{uc
($hexdumpcol)}])"};
}
}
my $ctlFile = $args{DIRECTORY}. '/' . lc($args{TABLE}) . '.ctl';
my $ctlFh = new IO::File();
$ctlFh->open("> $ctlFile") || die "cannot create file $ctlFile - $!
\n";
$ctlFh->print("load data\n");
$ctlFh->print("infile '$args{DUMPFILE}'\n");
$ctlFh->print("into table $args{TABLE}\n");
$ctlFh->print(q{fields terminated by ',' optionally enclosed by
'"'}. "\n");
$ctlFh->print("(\n");
$ctlFh->print( "\t" . join(",\n\t",_at_columns) . "\n");
$ctlFh->print(")\n");
$ctlFh->close;
my $parFile = $args{DIRECTORY}. '/' . lc($args{TABLE}) . '.par';
my $parFh = new IO::File();
$parFh->open("> $parFile") || die "cannot create file $parFile - $!
\n";
$parFh->print("userid = $args{SCHEMA}\n");
$parFh->print("control = " . lc($args{TABLE}) . ".ctl\n");
$parFh->print("log = " . lc($args{TABLE}) . ".log\n");
$parFh->print("bad = " . lc($args{TABLE}) . ".bad\n");
$parFh->close;
} Received on Wed Aug 27 2003 - 02:13:17 CEST
