7 sql2xls.pl - convert sql queries on file system to Excel file
11 Each file in current directory which ends in C<< *.sql >> will
12 be converted to Excel sheet. If you want to have specific order, you can
13 prefix filenames with numbers which will be striped when creating sheet
16 Comments in sql files (lines beginning with --) will be placed
17 in first line in bold.
19 To specify database on which SQL query is executed
20 C<< \c database >> syntax is supported.
22 You can also run script from command line, and it will produce
23 C<< sql_reports.xls >> file.
27 Dobrica Pavlinusic, dpavlin@rot13.org
31 use Spreadsheet::WriteExcel;
33 use CGI::Carp qw(fatalsToBrowser);
34 use CGI qw(path_translated);
35 use Encode qw/decode/;
36 use Data::Dump qw/dump/;
38 # edit following to set defaults
39 my $dsn = 'DBI:Pg:dbname=';
40 my $database = 'template1';
43 my $path = 'sql_reports.xls';
45 my $db_encoding = 'iso-8859-2';
46 my $xls_date_format = 'dd.mm.yyyy';
50 my $sql_dir = path_translated || '.';
51 $sql_dir =~ s,/[^/]+$,,;
53 opendir(DIR, $sql_dir) || die "can't opendir $sql_dir: $!";
54 my @sql_files = sort grep { /\.sql$/i && -f "$sql_dir/$_" } readdir(DIR);
58 if ($ENV{GATEWAY_INTERFACE} && $ENV{GATEWAY_INTERFACE} =~ m/CGI/i) {
60 print "Content-type: application/vnd.ms-excel\n\n";
61 $workbook = Spreadsheet::WriteExcel->new("-");
63 # Create a new Excel workbook
64 $workbook = Spreadsheet::WriteExcel->new( $path );
65 warn "Creating XLS file $path\n";
68 my $date_format = $workbook->add_format(num_format => $xls_date_format);
70 my $dbh = DBI->connect($dsn . $database,$user,$passwd, { RaiseError => 1, AutoCommit => 0 }) || die $DBI::errstr;
73 return decode( $db_encoding, shift );
76 foreach my $sql_file (@sql_files) {
78 my $sheet_name = $sql_file;
79 $sheet_name =~ s/\d+_//;
80 $sheet_name =~ s/_/ /g;
81 $sheet_name =~ s/\.sql//;
84 my $worksheet = $workbook->addworksheet($sheet_name);
86 print STDERR "working on $sql_file\n" if ($debug);
88 open(SQL,$sql_file) || die "can't open sql file '$sql_file': $!";
94 $dbh->disconnect if $dbh;
95 print STDERR "## connect to $1\n" if $debug;
96 $dbh = DBI->connect($dsn . $1,$user,$passwd, { RaiseError => 1, AutoCommit => 0 }) || die $DBI::errstr;
105 $sql =~ s/\s\s+/ /gs;
107 print STDERR "sql: $sql\ncomment: $comment\n" if ($debug);
113 # Add and define a format
114 my $fmt_comment = $workbook->addformat(); # Add a format
115 $fmt_comment->set_bold();
117 $worksheet->write($row, 0, _c($comment), $fmt_comment);
121 my $sth = $dbh->prepare($sql);
124 my $fmt_header = $workbook->addformat(); # Add a format
125 $fmt_header->set_italic();
127 for(my $col=0; $col<=$#{ $sth->{NAME} }; $col++) {
128 $worksheet->write($row, $col, ${ $sth->{NAME} }[$col], $fmt_header);
132 my @types = map { $dbh->type_info($_) ? $dbh->type_info($_)->{TYPE_NAME} : '?' } @{ $sth->{TYPE} };
134 while (my @row = $sth->fetchrow_array() ) {
135 for(my $col=0; $col<=$#row; $col++) {
136 my $data = $row[$col];
137 if ( $types[$col] =~ m/^date/i ) {
138 $data .= 'T' if $data =~ m/^\d\d\d\d-\d\d-\d\d$/;
139 $data =~ s/^(\d\d\d\d-\d\d-\d\d)\s(\d\d:\S+)$/$1T$2/;
141 $worksheet->write_date_time( $row, $col, $data, $date_format );
143 $worksheet->write($row, $col, _c( $data ) );