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

Manual Monks,

Need a fresh pair of eyes to point out what idiotic error I have in this syntax:

@price = ('12p', '18p'); @{$tbls{'12p'}} = [ 't72', 't73', 't74', 't75', 't76', 't77' ]; @{$bases_tbls{'18p'}} = [ 't73', 't74', 't75', 't76', 't77' ]; for $b (0 .. $#price) { $sql = 'SELECT respondent FROM'; for $i (0 .. $#{$tbls{$price[$a]}}) { $sql = $sql.' ${$tbls{$price[$a]}}[$i];'; $sta = $dbh -> prepare($sql); $sta -> execute() or die("Could not execute!" . $sta->errstr() +); ... a bunch of stuff ... } }
The execute produces an error that points to a syntax error "near '${$tbls{$price$a}}$i' " but I don't see it.

Thanks.

update - last sentence to fix inconsistency pointed out by DragonChild.

Forget that fear of gravity,
Get a little savagery in your life.

Replies are listed 'Best First'.
Re: Mixing up indices in multidimensional hash
by trammell (Priest) on Feb 16, 2005 at 19:39 UTC
    You have:
    @{$tbls{'12p'}} = [ 't72', 't73', 't74', 't75', 't76', 't77' ];
    Are you certain you don't want:
    $tbls{'12p'} = [ 't72', 't73', 't74', 't75', 't76', 't77' ];
    In addition, you can clean up your code considerably with the qw operator, eg.:
    $tbls{'12p'} = [ qw/ t72 t73 t74 t75 t76 t77 / ];

    Update: I also see a loop that starts:
    for $b (0 .. $#price) { ...
    Are you running with use strict? If not, you probably should be.

    Update: One more thing--looping over indices is rarely needed, and makes for ugly code. I think your loops should be more like:

    for my $price (@price) { $sql = 'SELECT respondent FROM'; for my $table (@{$tbls{$price}}) { ... } }
    This saves you the mental overhead of having to process all those array lookups.

      aw, heck, if you're going to start cleaning up the code with qw ...

      $tbls{'12p'} = [ 't72'..'t77' ];

      :-)))))

      Good point about the array declaration. Thanks.

      Actually, playing with it some more I'm finding that the problem is in the $sql = $sql.'...'

      I have my quotes in the wrong place, and, worse - the $sql just keeps getting tacked onto each iteration so it becomes a non-sensical command very quickly.

      I'll post it cleaned up in a few minutes.

      Forget that fear of gravity,
      Get a little savagery in your life.

Re: Mixing up indices in multidimensional hash
by dragonchild (Archbishop) on Feb 16, 2005 at 19:26 UTC
    And exactly where in the snippet you provided is {$bases_tbls{$age[$b]}}[$i]?

    A few thoughts

    • Don't use $a or $b - they are global variables reserved for sort.
    • Use strict. I'm betting there's a typo somewhere.
    • I'm not sure you really want to write your SQL like you have, but that's a topic for another thread.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Mixing up indices in multidimensional hash
by holli (Abbot) on Feb 16, 2005 at 19:21 UTC
    I commented out the stuff within the loop, because $dbh is undefined and get no syntax error. The error must be beforehand.


    holli, /regexed monk/
Re: Mixing up indices in multidimensional hash
by RazorbladeBidet (Friar) on Feb 16, 2005 at 19:58 UTC
    I agree it should probably be $tbls{'12p'} = ... not @{$tbls{'12p'}} (assuming you want an array reference).

    Another thing to note is that using @$arrayref is generally preferred over $#array. I'll try to find some actual information to back that up :)

    Update:

    Look here for this:

    The length of an array is a scalar value. You may find the length of array @days by evaluating $#days , as in csh. However, this isn't the length of the array; it's the subscript of the last element, which is a different value since there is ordinarily a 0th element. Assigning to $#days actually changes the length of the array. Shortening an array this way destroys intervening values. Lengthening an array that was previously shortened does not recover values that were in those elements. (It used to do so in Perl 4, but we had to break this to make sure destructors were called when expected.) If you evaluate an array in scalar context, it returns the length of the array. (Note that this is not true of lists, which return the last value, like the C comma operator, nor of built-in functions, which return whatever they feel like returning.)


    I thought there was more to it, but I may be looking in the wrong place. Either way, the $#array is the last subscript while scalar(@array) is the actual length.
      Yes, exactly. $#array is the last subscript while scalar(@array) is the actual length. Hence, using $#array as the last index in a for loop to loop through the array. I know some people prefer other styles, but I find that this keeps things very very explicit.

      Forget that fear of gravity,
      Get a little savagery in your life.

Re: Mixing up indices in multidimensional hash
by punch_card_don (Curate) on Feb 16, 2005 at 20:04 UTC
    OK, got it.

    The problem was manifold.

    First, DragonChild correctly pointed out that the original array declaration should have been

    $bases_tbls{'18p'} = [ 't73', 't74', 't75', 't76', 't77' ];
    Then, the line
    $sql = 'SELECT respondent FROM';
    was incorrectly placed. It should have been integrated into the loop, otherwise the line just got new items tacked onto it making a nonsensiscal sql command.

    Finally, the right way to refer to the element was

    $tbls{$price[$g]}[$i]
    Thanks for the help, all. One of the few drawbacks of being an independent is the lack of other humans in the office to bounce problems off of.

    Forget that fear of gravity,
    Get a little savagery in your life.