use Text::CSV_XS qw( csv ); my @records = ( { AB1 => 100, NN => 200, XYZ => 400}, { AB1 => 100, XYZ => 400, MM => 300}, ); my %fld = map { $_ => 1 } map { keys %$_ } @records; csv (in => \@records, headers => [ sort keys %fld ]); #### use Text::CSV_XS qw( csv ); my @records = ( { AB1 => 100, NN => 200, XYZ => 400 }, { AB1 => 200, XYZ => 400, MM => 300 }, { AB1 => 300, XYZ => undef, MM => "" }, ); my %seen; my @fld = sort grep { !$seen{$_}++ } map { keys %$_ } @records; csv (in => \@records, headers => \@fld, quote_empty => 1, on_in => sub { foreach my $f (@fld) { exists $_{$f} or $_{$f} = "--missing--"; } }); #### AB1,MM,NN,XYZ 100,--missing--,200,400 200,300,--missing--,400 300,"",--missing--,