I'm new at coding and so here.
Right now I'm creating an perl script, which automatically creates an excel file with the output of an SQL Query.
SQL Query:
init_db_connections();
my #row;
my $curHnd = INV::DBI::execute('----'.':------') or die $INV::DBI::errstr;
while ($row[0] = $curHnd->fetchrow_hashref()) {
printf("Row1: >%s<\n", $row[0]{Row1}),
printf("Row2: >%s<\n", $row[0]{Row2}),
printf("Row3: >%s<\n", $row[0]{Row3})
}
exit 0;
sub init_db_connections {
INV::DBI::init({
------ => '--------',
------- => q{select Row1, Row2, Row3
from table1
}
Create the Excel:
my $workbook = Excel::Writer::XLSX->new( 'perl.xlsx' );
my $worksheet = $workbook->add_worksheet();
my $format = $workbook->add_format();
$format->set_bold();
$format->set_color( 'black' );
$format->set_underline;
my $col = my $row = 0;
$worksheet->write( $row, $col, 'SQL Report', $format );
$workbook->close();
My Problem is now that i don't know how i can combine these two, so that the Query gets automatically pushed into the Excel.
Any Ideas would be great.
I think your problem is with the hashref and dereferencing it properly. It's a subtle mistake easily made when just starting out.
my $hashref;
while ( $hashref = $curHnd->fetchrow_hashref() ) {
printf("Row1: >%s<\n", $hashref->{Row1}),
printf("Row2: >%s<\n", $hashref->{Row2}),
printf("Row3: >%s<\n", $hashref->{Row3})
}
A hashref is a reference to a hash and they are sweet, especially when you use postfix dereferencing like I've done in the example.
The $hash{row1} code you were using is for accessing the value for row1 in %hash. (and for completeness, the old way of dereferencing a hashref would be ${$hashref}{row1} )
You don't really need #row array there. You were only ever assigning to the first element $row[0], so why not just use a scalar.
As for writing out to Excel, I think you'll be using the write method inside the while loop and incrementing the row counter with $row++ .
If you're going to be doing a lot of DBI coding, pick up a copy of Programming the Perl DBI by Descartes and Bunce for chapters 4 and 5. Old but still incredibly useful. (still got mine)
Does function CSV->PRINT only accept array reference? I am pushing $cell2_value in an array and then printing the array (i.e rows), it would be nice if I can directly write $cell2_value into an opened CSV file.
Things to take care of -
Excel cell having commas in their value would print in double-quotes.
Excel cells having "keyword" in their value would print the whole-cell value in double-quotes and inner quotes will change to ""keyword"".
I can write a CSV file with a few undesired outputs of excel cells. its inserting double quotes whenever it sees special characters like / or *.
CSV FILE from the below code:-
"CLASS_A,,x,Singapore,,0xABCF00C4,"/* x2-4Rw */",-,,,,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"CHECK- ""CLASS_B""- WORKED",1,2,3"
"CLASS_A,,,malyaisa,," 3:0","/* ABCVF */",E,,,,,,,Yes,,,,,,,,,,,,,Yes,,,,,,Yes,Yes,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
Desired output
CLASS_A,,x,malyaisa,,0xABCF00C4,/* x2-4Rw */,-,,,,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"CHECK- ""CLASS_B""- WORKED",1,2,3
CLASS_A,,,malyaisa,, 3:0,/* ABCVF */,E,,,,,,,Yes,,,,,,,,,,,,,Yes,,,,,,Yes,Yes,Yes,,,,,,,,,,,,,,,,,,,
Why it's inserting quotes around each line? Is there any way to remove it?
sub Excel_to_CSV
{
($student_excel_file) = #_;
if($student_excel_file ne "")
{
$student_excel_out_csv_file = $student_excel_file;
$student_excel_out_csv_file =~ s/.xlsm$/_new.csv/;
my $parser_1 = Spreadsheet::ParseXLSX->new();
my $workbook = $parser_1->parse($student_excel_file);
my $csv_1 = Text::CSV->new ({ binary => 1, auto_diag => 1, sep_char => ',' });
open my $fh, ">:encoding(utf-8)", $student_excel_out_csv_file or die "failed to create $student_excel_out_csv_file: $!";
if ( !defined $workbook )
{
die $parser_1->error(), ".\n";
}
my $worksheet=$workbook_->worksheet(0);
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
printf("Copyig Sheet: %s from the provided student \n", $worksheet->{Name});
my $concurentEmptyLineCount = 0;
for my $row_1 ( $row_min .. $row_max )
{
my #row_elements_array;
for my $col_1 ( $col_min .. $col_max )
{
my $cell_1 = $worksheet->get_cell( $row_1, 0 );
next unless $cell_1;
$concurentEmptyLineCount=0;
my $cell_2 = $worksheet->get_cell( $row_1, $col_1);
my $cell2_value =$cell_2 -> {Val};
if(defined $cell2_value)
{
push(#row_elements_array, $cell2_value);
}
else
{
my $blank="";
push(#row_elements_array, $blank);
}
}
my $next_line="\n";
push(#row_elements_array, $next_line);
my #temp_row_elements_array= #row_elements_array;
$csv_1->print($fh, \#temp_row_elements_array);
}
close $fh;
}
return $student_excel_out_csv_file;
}
Based on my understanding of your requirements, one solution is to remove the extraneous double-quotes from $cell2_value before pushing it into #row_elements_array. For example:
$cell2_value =~ s/"(")*/$1/g;
push(#row_elements_array, $cell2_value);
I am new to perl.
i have an excel sheet with lot of data.. I need to update it and create a graph based on the data..using perl.
i am succeded in updating an existing excel..
now adding chart to it is not happening
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::SaveParser;
use Spreadsheet::WriteExcel;
# Open an existing file with SaveParser
my $parser = Spreadsheet::ParseExcel::SaveParser->new();
my $template = $parser->Parse('MyExcel.xls');
my $worksheet = $template->worksheet('Firstsheet');
my $chart = $template->add_chart( type => 'line' );
$chart->add_series(
categories => '=URV!$A$17:$A$442',
values => '=URV!$D$17:$D$442',
name => 'pended graph',
);
This is not working.
Can't call method "add_chart" on an undefined value at charts4.ps line 20
Please help me with a sample working code..
Want to know whats the problem here.
add_chart() is one of the WORKBOOK METHODS. Try code like this:
use Spreadsheet::WriteExcel;
my $workbook = Spreadsheet::WriteExcel->new('perl.xls');
$worksheet = $workbook->add_worksheet();
$worksheet->write('A1', 'Hi Chart!');
my $chart = $workbook->add_chart( type => 'line', embedded => 1, name => 'pended graph' );
# Insert the chart into the a worksheet.
$worksheet->insert_chart( 'E2', $chart );
Update
The problem is that excel is very hard to update with perl.
An Excel file is a binary file within a binary file. It contains
several interlinked checksums and changing even one byte can cause it
to become corrupted.
As such you cannot simply append or update an Excel file. The only way
to achieve this is to read the entire file into memory, make the
required changes or additions and then write the file out again.
Spreadsheet::ParseExcel will read in existing excel files:
my $parser = Spreadsheet::ParseExcel->new();
# $workbook is a Spreadsheet::ParseExcel::Workbook object
my $workbook = $parser->Parse('blablabla.xls');
What you really want is Spreadsheet::ParseExcel::SaveParser, which is a combination of Spreadsheet::ParseExcel and Spreadsheet::WriteExcel.
Here is an example.
Summing it up, I would suggest you to read the excel data in and then try either of the following:
Create another xls file and use the Spreadsheet::WriteExcel::Chart
library.
Create a xlsx file and use the Excel::Writer::XLSX::Chart library.
Another close option would be to read the excel in with
Spreadsheet::ParseExcel::SaveParser and then add the chart and save
it, but with this module all original charts are lost.
If you are on a Windows machine you may try to use Win32::OLE.
Here is the example from Win32::OLE's own documentation:
use Win32::OLE;
# use existing instance if Excel is already running
eval {$ex = Win32::OLE->GetActiveObject('Excel.Application')};
die "Excel not installed" if $#;
unless (defined $ex) {
$ex = Win32::OLE->new('Excel.Application', sub {$_[0]->Quit;})
or die "Oops, cannot start Excel";
}
# get a new workbook
$book = $ex->Workbooks->Add;
# write to a particular cell
$sheet = $book->Worksheets(1);
$sheet->Cells(1,1)->{Value} = "foo";
# write a 2 rows by 3 columns range
$sheet->Range("A8:C9")->{Value} = [[ undef, 'Xyzzy', 'Plugh' ],
[ 42, 'Perl', 3.1415 ]];
# print "XyzzyPerl"
$array = $sheet->Range("A8:C9")->{Value};
for (#$array) {
for (#$_) {
print defined($_) ? "$_|" : "<undef>|";
}
print "\n";
}
# save and exit
$book->SaveAs( 'test.xls' );
undef $book;
undef $ex;
UPDATE#2
Here is an example code:
use strict;
use Spreadsheet::WriteExcel;
my $workbook = Spreadsheet::WriteExcel->new( 'chart_column.xls' );
my $worksheet = $workbook->add_worksheet();
my $bold = $workbook->add_format( bold => 1 );
# Add the worksheet data that the charts will refer to.
my $headings = [ 'Category', 'Values 1', 'Values 2' ];
my $data = [
[ 2, 3, 4, 5, 6, 7 ],
[ 1, 4, 5, 2, 1, 5 ],
[ 3, 6, 7, 5, 4, 3 ],
];
$worksheet->write( 'A1', $headings, $bold );
$worksheet->write( 'A2', $data );
###############################################################################
#
# Example 1. A minimal chart.
#
my $chart1 = $workbook->add_chart( type => 'column', embedded => 1 );
# Add values only. Use the default categories.
$chart1->add_series( values => '=Sheet1!$B$2:$B$7' );
# Insert the chart into the main worksheet.
$worksheet->insert_chart( 'E2', $chart1 );
###############################################################################
#
# Example 2. One more chart
#
my $chart2 = $workbook->add_chart( type => 'column', embedded => 1 );
# Configure the chart. # change the categories if required change the values as required
$chart2->add_series(
categories => '=Sheet1!$A$4:$A$7',
values => '=Sheet1!$B$4:$B$7',
);
$worksheet->insert_chart( 'N1', $chart2, 3, 3 );
Also,
If you don't mind xlsx over xls, you may use Excel::Writer::XLSX. It is more actively maintained.
The trick to be able to parse and use at the same time the functions inside the WriteExcel module is to use the the use Spreadsheet::ParseExcel::SaveParser; module.
Below i have an example. The example will not use the chart functions but the problem you have is not on how to use the chart functions of WriteExcel module but on how to parse an existing excel file and then use that parsed information with the WriteExcel modul (which is originally thought only for NEW excel files).
if ( ( -f $excel_file_name ) && ( ( stat $excel_file_name )[7] > 0 ) ) {
#PARSE EXCEL
use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::SaveParser;
# Open the template with SaveParser
my $parser = new Spreadsheet::ParseExcel::SaveParser;
my $template = $parser->Parse("$excel_file_name");
my $sheet = 0;
my $row = 0;
my $col = 0;
if ( !defined $template ) {
die $parser->error(), " Perlline:", __LINE__, " \n "; #probably the file is already open by your GUI
}
# Get the format from specific cell
my $format = $template->{Worksheet}[$sheet]->{Cells}[$row][$col]->{FormatNo};
# Add a new worksheet
#for my $worksheet ( $template->worksheets() ) {
my $worksheet_parser = $template->worksheet("$metrict_data_worksheet_name");
my ( $row_min, $row_max ) = $worksheet_parser->row_range();
my ( $col_min, $col_max ) = $worksheet_parser->col_range();
my #row_array_value;
for my $row ( 1 .. $row_max ) { #avoid header start from 1
for my $col ( $col_min .. $col_max ) {
my $cell = $worksheet_parser->get_cell( $row, $col );
next unless $cell;
#print "Row, Col = ($row, $col)\n";
#print "Value = ", $cell->value(), "\n";
#print "Unformatted = ", $cell->unformatted(), "\n";
#print "\n";
push( #row_array_value, $cell->value() );
} #end header column loops for one regression
} #end row loop all lines
#}
# The SaveParser SaveAs() method returns a reference to a
# Spreadsheet::WriteExcel object. If you wish you can then
# use this to access any of the methods that aren't
# available from the SaveParser object. If you don't need
# to do this just use SaveAs().
#
my $workbook;
{
# SaveAs generates a lot of harmless warnings about unset
# Worksheet properties. You can ignore them if you wish.
local $^W = 0;
# Rewrite the file or save as a new file
my $check_if_possible2write = Spreadsheet::WriteExcel->new($excel_file_name);
if ( defined $check_if_possible2write ) { #if not possible it will be undef
$workbook = $template->SaveAs("$excel_file_name");#IMPORTANT this is of type WriteExcel and not ParseExcel
}
else {
print "Not possible to write the Excel file :$excel_file_name, another user may have the file open. Aborting... ", __LINE__, " \n ";
exit;
}
}
#####################FROM HERE YOU CAN USE AGAIN use Spreadsheet::WriteExcel; ####################
use Spreadsheet::WriteExcel;
my $worksheet = $workbook->sheets("$metrict_data_worksheet_name");
my $column_header_count = 0;
foreach my $name ( sort { lc $a cmp lc $b } keys %merged_all_metrics ) {
$worksheet->write( $row_max + 1, $column_header_count, "$merged_all_metrics{$name}" ); #row,col start
$column_header_count++;
}
$worksheet->set_column( 'A:L', 50, undef, 0, 1, 0 ); #grouping #comp_src group
$worksheet->set_column( 'N:R', 50, undef, 0, 1, 0 ); #grouping
$workbook->close() or die "Error closing file: $!"; #CLOSE
}
The important part of the code is what happens after the comment line:
#####################FROM HERE YOU CAN USE AGAIN use Spreadsheet::WriteExcel; ####################
After that point you will see that you have a $workbook handler. This variable has all the information parsed and more important is that it is from type WriteExcel Object so you will have all the methods of this module available.
Important Notice. The parser is not able to parse charts and formulas (only values), therefore you will have to write then again on each parse->write loop.