Txn ID, Name , Type , Product ID, Qty, Gross 010 , Moe , Cart , , 1 , 15 010 , Moe , Item , widget-1 , 1 , 15 020 , Larry, Cart , , 3 , 35 020 , Larry, Item , widget-1 , 1 , 15 020 , Larry, Item , widget-2 , 2 , 20 #### Txn ID, Name , Qty, Gross, widget-1 Qty, widget-1 Gross, widget-2 Qty, widget-2 Gross 010 , Moe , 1 , 20 , 1 , 15 , , 020 , Larry, 3 , 35 , 1 , 15 , 2 , 20 #### #!/usr/bin/perl use strict; use Text::CSV; use Data::Dumper; my $report_file = '/files/report.csv'; my $csv_file = '/files/custom.csv'; my $csv = Text::CSV->new ( { allow_whitespace => 1, binary => 1, sep_char => ',' } ) or die "Cannot use CSV: ".Text::CSV->error_diag (); my $csv_fh; open ($csv_fh, "<:encoding(utf8)", $csv_file) or die "$csv_file : $!"; # declare column names for getline_hr $csv->column_names($csv->getline($csv_fh)) or die "$csv_file : $!"; my @records = (); my @temp = (); my %column_order = (); my $ci= 0; while (my $row = $csv->getline_hr($csv_fh)) { my $key; my $value; if (${$row}{'Type'} eq 'Shopping Cart Payment Received') { # push (@records, \@temp) if @temp; EDITED: THIS LINE RESULTED IN OVERWRITTEN DATA push (@records, [@temp]) if @temp; # THIS SEEMS TO WORK, SEE MY COMMENT BELOW @temp = (); while (($key, $value) = each %{$row}) { ${%column_order}{$key} = $ci++ unless (defined ${%column_order}{$key}); $temp["${%column_order}{$key}"] = $value; } } elsif (${$row}{'Type'} eq 'Shopping Cart Item') { # more code to add append to first row ) } my $report_fh; open ($report_fh, ">:encoding(utf8)", $report_file) or die "$report_file : $!"; for my $key (sort {$column_order{$a}<=>$column_order{$b}} keys %column_order) { print $report_fh "$key" , ", "; } print $report_fh "\n"; for my $record (@records) { print $report_fh join(", ",@$record), "\n"; } print $report_fh "\n";