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

I'm having some trouble dynamically declaring a number of arrays that are used to store the result set from a query. Below is a short example:
my $sth1 = $dbh->prepare($full_query); $sth1->execute(); # fetch the records while (@data = $sth1->fetchrow_array()) { push @field1, $data[0]; push @field2, $data[1]; push @field3, $data[2]; } $sth1->finish;
So I would like to have @field1, @field2, @field3 created dynamically based on the number of fields in my table. And then be able to populate each array in the while loop.

Replies are listed 'Best First'.
Re: declaring arrays dynamically
by herveus (Prior) on Sep 14, 2004 at 17:36 UTC
    Howdy!

    Do you mean you want a variable number of arrays, @field1, @field2, ... @fieldn where you have n columns, depending on the query?

    If so, you could do that, but you really don't want to go that route. Instead, you might consider an array of arrays.

    something like:

    while (@data = $sth1->fetchrow_array()) { my $col = 0; foreach my $coldata (@data) { push @{$fields[$col]}, $coldata; $col++; } }
    should make @fields be an array with one element per column, and each of those elements will be a reference to an array holding the values from each row in row order.

    Does that get you where you were trying to go?

    yours,
    Michael

      Well ... you could do that ... ;) or you could do this:

      use DBI; use Data::Dumper; use Math::Matrix; my $dbh = DBI->connect( qw(DBI:vendor:database:host user pass), {RaiseError=>1}, ); my $sth = $dbh->selectall_arrayref('select id,first,last from user'); my $matrix = Math::Matrix->new(@$sth); print Dumper $matrix->transpose;
      Use the CPAN. Write more glue code. :)

      jeffa

      L-LL-L--L-LL-L--L-LL-L--
      -R--R-RR-R--R-RR-R--R-RR
      B--B--B--B--B--B--B--B--
      H---H---H---H---H---H---
      (the triplet paradiddle with high-hat)
      
Re: declaring arrays dynamically
by Old_Gray_Bear (Bishop) on Sep 14, 2004 at 17:37 UTC
    Sounds like you want an Arrary of Arrays here. Pseudo Code:
    my $sth1 = $dbh->prepare($full_query); $sth1->execute(); my @data_aoa = []; while (@data = $sth1->fetchrow_array()) { push @data_aoa[0], $data[0]; push @data_aoa[1], $data[1]; push @data_aoa[2], $data[2]; } . . . $sth1->fini

    ----
    I Go Back to Sleep, Now.

    OGB

      Why use pseudocode which is only a few chars different than the real code?

      my $sth1 = $dbh->prepare($full_query); $sth1->execute(); my @data_aoa; while (@data = $sth1->fetchrow_array()) { push @{$data_aoa[0]}, $data[0]; push @{$data_aoa[1]}, $data[1]; push @{$data_aoa[2]}, $data[2]; } $sth1->finish()
Re: declaring arrays dynamically
by CountZero (Bishop) on Sep 14, 2004 at 19:24 UTC
    Have a look at the DBI-docs for the fetchall_arrayref function.

    $tbl_ary_ref = $sth->fetchall_arrayref; returns a reference to an array each element of which is a reference to an array containing the data for each field in this row.

    You can traverse this structure, so as to emulate your "1 array per field" requirement:

    foreach (@$tbl_ary_ref) { print "@$_[1]\n"; # print the values of the second field in the da +tabase }

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: declaring arrays dynamically
by zdog (Priest) on Sep 14, 2004 at 17:52 UTC

    Alternatively, if you'd like more descriptive field names, you could construct a hash of array refs as follows:

    my $sth1 = $dbh->prepare($full_query); $sth1->execute(); my $fields = {}; my $hashref; while ( $hashref = $sth1->fetchrow_hashref ) { for ( keys %$hashref ) { push @{ $fields->{$_} }, $hashref->{$_}; } } $sth1->finish; # data is in $fields

    (Code untested). Take a look at the fetchrow_hashref() method in the DBI docs.

    Zenon Zabinski | zdog | zdog@perlmonk.org

Re: declaring arrays dynamically
by radiantmatrix (Parson) on Sep 14, 2004 at 18:06 UTC
    Other replies are right on the nose, you probably want an array of arrays. However, if there is some reason you can't do that (though I can't imagine why not):
    while (@data = $sth1->fetchrow_array()) { for (my $field = 0; $field <= $#data ; $field++) { my $var_cnt = $field+1; #needed for cat in next line to work eval('push @field'.$var_cnt.', $data['.$field.'];'); } }
    That would generate @field1, @field2,... @fieldn for the width of your row. Using an array of arrays or even a hash would work better. A hash method:
    my %results; while ($data = $sth1->fetchrow_hashref) { foreach (keys %$data) { push $reults{$_}, $$data{$_}; } }
    %results is now a hash of arrays. $results{degree} contains an array of all values for the field "degree" in your table. These can be extracted by:
    foreach (keys %results) { print "Results for column $_:\n"; foreach (@{$results{$_}}) { print " $_\n"; } }
    Or something like it.
    --
    $me = rand($hacker{perl});

      For fun,

      while (@data = $sth1->fetchrow_array()) { for (my $field = 0; $field <= $#data ; $field++) { my $var_cnt = $field+1; #needed for cat in next line to work eval('push @field'.$var_cnt.', $data['.$field.'];'); } }

      can be rewritten as

      { no strict 'refs'; while (@data = $sth1->fetchrow_array()) { for (my $field = 0; $field <= $#data ; $field++) { my $var_name = 'field' . ($field+1); push(@$var_name, $data[$field]); } } }

      to eliminate the costly eval. You lose the ability to write to lexicals (my vars), although using those is just asking for trouble in this scenario.

      A here's version (with the same caveat as the previous one) that works without (even partially) turning off strict:

      my $pkg = \%::; $pkg = $pkg->{$_.'::'} foreach (split(/::/, __PACKAGE__)); while (@data = $sth1->fetchrow_array()) { for (my $field = 0; $field <= $#data ; $field++) { push(@{$pkg->{'field' . ($field+1)}}, $data[$field]); } }

      Symtab manipulation is so much fun!