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

Monks,

I'm still a newbie and am having problems with arrays created from output with DBI.

I've got a table with two columns; one is an address(VARCHAR), the other is an arbitrary id number (INT). An earlier query based on the same code successfully creates an array of addresses. The bit I'm having trouble with tries to create a corresponding array of id numbers for that address array.

My, very basic, code (using strict and warnings) looks like this:

foreach $addr (@addr){ $addr_lookup = "SELECT u2addr.id FROM u2addr WHERE u2addr.addr = \ +"$addr\";"; $stm = $dbh->prepare($addr_lookup); $stm->execute; @results=(); @row=(); while (my @row = $stm->fetchrow_array){ push (@results, @row); }#end of while $stm->finish; print $results[-1]; }

Now the problem is that the elements of the array @results don't appear to have an index, so the $results[-1] throws back all the content of @result.

I've tried reworking the code to use selectcol_arrayref, as per the DBI recipes, but no change.

To make matters more frustrating, if I pull the output of the fetchrow_array into a scaler al la:

while (my ($uid_value) = $stm->fetchrow_array){ print "$uid_value, "; }#End of While
the output is individual values followed by a comma, so the database output is as expected. However, if i try and push the scaler values into an array this array also has no index and an $results[-1] throws back all the content...

I know the code I'm using is primitive but what am I missing here?

Jon

Replies are listed 'Best First'.
Re: An Array Without and Index
by Marshall (Canon) on Aug 13, 2012 at 08:58 UTC
    I'm not sure what is going on here.
    Prepare the statement before starting the loop (do it only once)
    Execute the statement, filling in the placeholder (?) within the loop
    my $addr_lookup = 'SELECT u2addr.id FROM u2addr WHERE u2addr.addr = ?'; my $stm = $dbh->prepare($addr_lookup); foreach my $addr (@addr) { $stm->execute($addr); my @results=(); while (my @row = $stm->fetchrow_array) { push (@results, [@row]); #push array ref to @row #using new memory and copy of @row #could also just fetchrow_arrayref } ## do something with @results here... ## perhaps: "print Dumper \@results;" ## to see what you have in @results? }
Re: An Array Without and Index
by Anonymous Monk on Aug 13, 2012 at 08:46 UTC

    I know the code I'm using is primitive but what am I missing here?

    1) you're not using placeholders, and you're probably not using quote( see http://bobby-tables.com/ )

    2) and you're preparing way too much (prepare once outside of loop, then ->execute($addr); inside loop )

    The situation you describe is hard to believe, so you're better off using Data::Dump::dd for debugging instead of print

Re: An Array without an Index
by Athanasius (Archbishop) on Aug 13, 2012 at 09:01 UTC

    Hello Toppo, and welcome to the Monastery!

    Two quick observations:

    1. @row=(); while (my @row = $stm->fetchrow_array){

      The my in the while loop creates a new @row variable each time through the loop. This is almost certainly not what you wanted. Update: You don’t want both! See the comment by Anonymous Monk, below.

    2. the array @results don't appear to have an index

      I don’t know what you’re trying to say here, but be assured that every element in every array has an index! See e.g. perldata.

    I think more information is required before the monks can help you. Please provide a minimal but complete, working script that demonstrates the problem, along with sample input, and a description of the desired output.

    HTH,

    Athanasius <°(((><contra mundum

      The my in the while loop creates a new @row variable each time through the loop. This is almost certainly not what you wanted.

      Actually it most certainly is -- the @row=(); is what is an error -- probably because OP isn't using strict and warnings

        He said the program runs under strict and warnings.

        But the @row = () and the my @row in the while loop are two distinct variables. Since he is not using the first @row, it does not seem to be the cause of his problems.

        CountZero

        A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

        My blog: Imperial Deltronics
Re: An Array Without and Index
by Neighbour (Friar) on Aug 13, 2012 at 09:08 UTC
    If your u2addr-table isn't extraordinary large, you could just fetch the whole thing in a hashref and loop through that:
    my @results; my $hr_addresses = $dbh->selectall_hashref("SELECT addr, id FROM u2add +r", "addr"); if (!defined $hr_addresses) { die("Error executing query: " . $dbh->er +rstr); } foreach my $addr (@addr) { if (defined $hr_addresses->{$addr}) { push(@results, $hr_addresses->{$addr}) } else { print("Error, ID of address [$addr] not found\n"); } }
    The use of selectall_hashref (or selectall_arrayref) relieves you of having to prepare, execute and fetch* everything yourself. All that's left is to use the results (in this case as an in-memory hashed lookup for all addresses in @addr). On top of that, calling finish isn't neccesary when you are fetching *all* the results, only when you want to abort fetching results partly through.
    Besides that, if selectall_hashref (or selectall_arrayref) returns undef, then executing the query went wrong. This is a very nice thing to know. This is also different from the query executing correctly, but returning no results (which is slightly more difficult to check when using fetchrow_array).

    Edit: Whoops, got the keyfield of the query wrong, fixed now.
Re: An Array Without and Index
by CountZero (Bishop) on Aug 13, 2012 at 13:50 UTC
    I will not repeat the comments already made by the other Monks. I just wondered why you first select a list of addresses from the database and then plug in each address one by one in a new select statement to fetch the related IDs.

    Unless you made some changes to the array of addresses, it should be possible to fetch the adresses and their IDs in one select statement. That will really speed-up your program.

    When using databases, it is my experience that it is almost always "best" (= faster or less memory use or easier) to let the database do all the heavy lifting and only reserve the really difficult parts (like formatting or calculating or transforming the data) for your program.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

    My blog: Imperial Deltronics
Re: An Array Without and Index
by aaron_baugher (Curate) on Aug 13, 2012 at 12:32 UTC

    All arrays have an index, so that's not the problem here. Other people have given you good advice about using placeholders, moving your prepare statement outside your loop, etc. But to narrow down your problem, try adding some debugging statements, like this:

    print "Fetching values for $addr\n"; while (my @row = $stm->fetchrow_array){ print " Got values: ", join( ':', @row ), "\n"; push (@results, @row); } $stm->finish; print "Finished getting values, printing \@results for $addr:\n"; print join ':', @results; print "\n\n";

    Aaron B.
    Available for small or large Perl jobs; see my home node.

      try adding some debugging statements, like this:

      No :) use Data::Dump / Data::Dumper... for visualizing data structures

        I use those a lot, to the point where I'm thinking of putting 'use Data::Printer' in the blank template I use to start a new Perl script, since I always end up adding it during testing anyway. But in this case, there are two reasons I didn't:

        • Those modules print several lines to show a single value. That's fine to display a single structure once at a certain point, but to do it repeatedly in a loop can give you a heap of output that would be difficult for a newbie to parse through.
        • I have a feeling his real problem is with program flow. I think he's going to discover that where he thinks he's seeing the whole array printed, he's really seeing one element of the array printed each time through the loop, but with nothing else being printed between them, they look like one output. To see that, he doesn't need to see the structure of @results just once; he needs to see how his program is flowing and how that array is changing with each step.

        So in this case, in my opinion, changing my print/join statements to 'print Dumper @results' could make it harder for him to see the problem.

        Aaron B.
        Available for small or large Perl jobs; see my home node.