How can I export an Oracle table to tab separated values?
I need to export a table in the database to a tab separated values file. I am using DBI on Perl and SQLPlus. Does it support (DBI or开发者_如何学C SQLPlus) exporting and importing to or from TSV files?
I can write a code to do my need, But I would like to use a ready made solution if it is available.
It should be relatively simple to dump a table to a file with tab-separated values.
For example:
open(my $outputFile, '>', 'myTable.tsv');
my $sth = $dbh->prepare('SELECT * FROM myTable');
$sth->execute;
while (my $row = $sth->fetchrow_arrayref) {
print $outputFile join("\t", @$row) . "\n";
}
close $outputFile;
$sth->finish;
Note that this will not work well if your data contains either a tab or a newline.
From the information you have provided I am guessing you are using DBI to connect to an Oracle instance (since you mentioned sqlplus).
If you want a "ready made" solution as you have indicated, your best bet is to use "yasql
" (Yet Another SQLplus) a DBD::Oracle based database shell for oracle.
yasql has a neat feature that you can write an sql select statement and redirect the output to a CSV file directly from its shell (You need Text::CSV_XS) installed for that.
On the other hand you can roll your own script with DBD::Oracle and Text::CSV_XS. Once your statement handles are prepared and executed, all you need to do is:
$csv->print ($fh, $_) for @{$sth->fetchrow_array};
Assuming you have initialised $csv with tab as record separator. See the Text::CSV_XS Documentation for details
Here's an approach with awk and sqlplus only. You can use store the awk script or copy/paste the oneliner. It uses the HTML output mode so that fields are not clobbered.
Store this script as sqlplus2tsv.awk:
# This requires you to use the -M "HTML ON" option for sqlplus, eg:
# sqlplus -S -M "HTML ON" user@sid @script | awk -f sqlplus2tsv.awk
#
# You can also use the "set markup html on" command in your sql script
#
# Outputs tab delimited records, one per line, without column names.
# Fields are URI encoded.
#
# You can also use the oneliner
# awk '/^<tr/{l=f=""}/^<\/tr>/&&l{print l}/^<\/td>/{a=0}a{l=l$0}/^<td/{l=l f;f="\t";a=1}'
# if you don't want to store a script file
# Start of a record
/^<tr/ {
l=f=""
}
# End of a record
/^<\/tr>/ && l {
print l
}
# End of a field
/^<\/td>/ {
a=0
}
# Field value
# Not sure how multiline content is output
a {
l=l $0
}
# Start of a field
/^<td/ {
l=l f
f="\t"
a=1
}
Didn't test this with long strings and weird characters, it worked for my use case. An enterprising soul could adapt this technique to a perl wrapper :)
I have had to do that in the past... I have a perl script that you pass the query you wish to run and pipe that through sqlplus. Here is an excerpt:
open(UNLOAD, "> $file"); # Open the unload file.
$query =~ s/;$//; # Remove any trailng semicolons.
# Build the sql statement.
$cmd = "echo \"SET HEAD OFF
SET FEED OFF
SET COLSEP \|
SET LINES 32767
SET PAGES 0
$query;
exit;
\" |sqlplus -s $DB_U/$DB_P";
@array = `$cmd`; # Execute the sql and store
# the returned data in "array".
print $cmd . "\n";
clean(@array); # Remove any non-necessary whitespace.
# This is a method to remove random non needed characters
# from the array
foreach $x (@array) # Print each line of the
{ # array to the unload file.
print UNLOAD "$x\|\n";
}
close UNLOAD; # Close the unload file.
Of course above I am making it pipe delimeted... if you want tabs you just need the \t instead of the | in the print.
精彩评论