ravi45722 has asked for the wisdom of the Perl Monks concerning the following question:

I got a small problem with .xls files. I am parsing a file. Its good completely except the merged rows using for headers(already merged in template) getting emerged after parsing & saving. I am not doing anything for that merged rows. I am just writing in below rows. Then why they are emerged????

My template is like this. Merged & center (3 rows) for each type of error.

------------------------------------------------ User Errors | Netowrk Errors | System Error | ------------------------------------------------

After parsing its getting emerging the cells like this.

------------------------------------------------ User| | | Netowrk | | | System | | | ------------------------------------------------

I am writing the code like this. Here I am not writing anything into that rows.

#!/usr/bin/perl use strict; use warnings; use DBI; use Spreadsheet::ParseExcel; use Spreadsheet::ParseExcel::SaveParser; my $date=$ARGV[1]; #yymmdd my $hour=$ARGV[0]; #06 $date or $date=`date --date='1 day ago' +%Y%m%d`; chomp $date; chomp $hour; my $db_name = "ravi"; my $table = "CDR"; my $sub_table = "Submission_Failures"; my $del_table = "Delivery_Failures"; my $host = "xxx.xx.x.xxx"; my $command = "cp /root/prac/CDR/CDR.xls /root/prac/CDR/CDR_Report_20$ +date$hour.xls"; print $command; `$command`; sub NULL_count { my $type = $_[0]; my @temp_array; my $error_db = DBI->connect("DBI:mysql:database=$db_name;host= +$host;mysql_socket=/opt/lampstack-5.5.27-0/mysql/tmp/mysql.sock","roo +t","", {'RaiseError' => 1}); my $error_sth = $error_db->prepare("SELECT Error_list from err +or_potrait WHERE Date='$date' and Type='$type'"); $error_sth->execute() or die $DBI::errstr; while (my $temp = $error_sth->fetchrow_array()) { push(@temp_array, $temp); } my $temp = @temp_array; foreach my $i ($temp .. 4) { $temp_array[$i] = "NULL"; } $error_sth->finish(); return @temp_array; } my @db_system_errors = NULL_count ("Submission_user_error"); my @db_network_errors = NULL_count ("Submission_ESME_error"); my @db_ESME_errors = NULL_count ("Submission_system_error"); my @db_user_errors = NULL_count ("Submission_network_error"); my @del_user_errors = NULL_count ("Delivery_user_error"); my @del_network_errors = NULL_count ("Delivery_network_error"); my @del_system_errors = NULL_count ("Delivery_system_error"); my @submission_errors = (@db_network_errors,@db_system_errors,@db_ESM +E_errors,@db_user_errors); my @delivery_errors = (@del_user_errors,@del_network_errors,@del_sy +stem_errors); sub error_headers { my $sheet_no = shift; my @array = @_; my $row = 1; my $col = 1; # Open an existing file with SaveParser my $parser = Spreadsheet::ParseExcel::SaveParser->new(); my $template = $parser->Parse("CDR_Report_20$date$hour.xls") o +r die "Cant open xls"; # Get the first worksheet. my $sheet = $template->worksheet($sheet_no); $sheet->AddCell( 1, 0, $date ); foreach my $value (@array) { $sheet->AddCell( $row, $col, $value ); ++$col; } $template->SaveAs("CDR_Report_20$date$hour.xls"); } error_headers (3,@submission_errors); error_headers (4,@delivery_errors); sub parser_excel { my $sql_comm = $_[0]; my $sheet_no = $_[1]; my $row = $_[2]; my $col = $_[3]; my $dbh = DBI->connect("DBI:mysql:database=$db_name;host=$host +;mysql_socket=/opt/lampstack-5.5.27-0/mysql/tmp/mysql.sock","root","" +, {'RaiseError' => 1}); #Selecting the data to fetch my $sth = $dbh->prepare("$sql_comm"); $sth->execute() or die $DBI::errstr; # Open an existing file with SaveParser my $parser = Spreadsheet::ParseExcel::SaveParser->new(); my $template = $parser->Parse("CDR_Report_20$date$hour.xls") o +r die "Cant open xls"; # Get the first worksheet. my $sheet = $template->worksheet($sheet_no); $sheet->AddCell( $_[4], 0, $date ); while (my @row = $sth->fetchrow_array()) { my $Date_db = shift @row; foreach my $value (@row) { $sheet->AddCell( $row, $col, $value ); ++$col; } $row++; $col=0; } $template->SaveAs("CDR_Report_20$date$hour.xls"); $sth->finish(); } parser_excel("Select * from $table where Date = $date and Hour = $hour +",2,1,0,0); parser_excel("Select * from $sub_table where Date = $date and Hour = $ +hour",3,2,0,1); parser_excel("Select * from $del_table where Date = $date and Hour = $ +hour",4,2,0,1);

Replies are listed 'Best First'.
Re: After parsing .xls the rows getting emerged
by GotToBTru (Prior) on Oct 08, 2015 at 12:28 UTC

    Are you confident in the number of columns in your @array and @row? select * is a potential problem if fields are ever added, renamed or removed.

    Dum Spiro Spero

      Thanks for reply. I know my array & row exactly. Depend on the DB I created the template. After seeing your reply I rechecked it. But I think if I have more columns in DB it will not effect the top rows. Its just go continuously. But in the .xls the headers (Merged cells) are presented in 0th row. I started writing from 2nd row. I am not making any changes for the above rows.

Re: After parsing .xls the rows getting emerged
by chacham (Prior) on Oct 08, 2015 at 14:39 UTC
    my $error_sth = $error_db->prepare("SELECT Error_list from error_potra +it WHERE Date='$date' and Type='$type'"); $error_sth->execute() or die $DBI::errstr;

    Don't use dynamic SQL! :) That is, don't stick variables directly in your statements. Use placeholders for security. It's really easy too. Something like:

    my $error_sth = $error_db->prepare("SELECT Error_list from error_potra +it WHERE Date=? and Type=?"); $error_sth->execute($date, $type) or die $DBI::errstr;

      I understand your concept. In uploading I am using place holders.(Not in this code)

      my @delivery_failure_array = ($db_date,"$hour",@del_user_error_count,@ +del_user_network_count,@del_user_system_count); $placeholders = join(',',('?') x scalar @delivery_failure_array); $delivery_sth = $delivery_db->prepare("insert into $delivery_table val +ues ($placeholders)"); $delivery_sth->execute(@delivery_failure_array) or die $DBI::errstr;

      Can you please explain how it increases the security??? I am not aware of that at all.

        Can you please explain how it increases the security?

        Most of work is behind the scenes. The DBI uses the placeholders to register a host variable via the database's CLI (call level interface.) When the values are passed to the CLI, they are contained and can only be values. Hence, no matter what is passed, it cannot adversely affect the statement.

        When placeholders are not used, the statement is not a statement until the variables are interpolated into the text. So, the statement might not be what it seems. Further, due to quoting and formatting, all sorts of things might need be done to variables, whereas placeholders need no such help. Finally, placeholders are (ultimately) strictly typed. Possibly making errors a little more sensible.

        This is aside from performance gains (when the statement (or, in some case, even a very similar statement) is executed multiple times) and self-documentation. Please, especially after doing the upload correctly and having this code most of the way there, don't use dynamic SQL.

Re: After parsing .xls the rows getting emerged
by tangent (Parson) on Oct 09, 2015 at 16:22 UTC
    The docs for Spreadsheet::ParseExcel::SaveParser state that the module works "by reading it with Spreadsheet::ParseExcel and rewriting it with Spreadsheet::WriteExcel". So any merged cells will be lost when re-writing. You will need to use the WriteExcel module to re-create the merged cells, which means you will have to separate the reading and writing in your own script.

    To merge the cells you use the "merge_range" method with a Format:
    my $format = $workbook->add_format( align => 'left' ); $worksheet->merge_range('A1:C1', 'New Value', $format);
    See the docs for Spreadsheet::WriteExcel