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

Hi, This code runs and inserts into the database but the $values[0] and $values[1} entries are incorrect, they are set to 0
my @nametape =( [24, 101], [25, 102], [23, 103], [21, 104], [26, 105], [22, 106], ); foreach $line (@nametape) { my @values = split(' ',$line); $products_id = $product_number; $options_id = 10; $options_values_id = $values[0]; $options_values_price = 0.00; $price_prefix = "+"; $products_options_sort_order = $values[1]; $query = $dbh->prepare(" INSERT INTO products_attributes (products_id, options_id, options_ +values_id, options_values_price, price_prefix, products_options_sort_ +order) VALUES ('$products_id', '$options_id', '$options_values_id', '$op +tions_values_price', '$price_prefix', '$products_options_sort_order') + "); $query->execute or exit; };
Why are the $values[0] and $values[1} entries not set correctly?

Replies are listed 'Best First'.
Re: foreach and lists
by kcott (Archbishop) on Mar 14, 2013 at 03:01 UTC

    G'day almoodie,

    There seems to be a few things you haven't really understood here:

    • @nametape is an array of arrayrefs.
    • When iterating through @nametape with foreach, each element will be an arrayref, not a line (i.e. $line is not what its name suggests).
    • split operates on a string. Such a string might often be found in variable called $line - but not today :-(
    • To access elements of an array you use $array[index]; for arrayrefs, you use $arrayref->[index] (where index evaluates to an integer).
    • Had you added "use strict;" and "use warnings;" to the start of your code, Perl would have alerted you to these types of problems. See strict and warnings.

    Here's an example of the type of code you need:

    $ perl -Mstrict -Mwarnings -E ' my @nametape = ([24, 101], [25, 102], [23, 103]); for my $arrayref (@nametape) { say "Arrayref values: ", $arrayref->[0], " and ", $arrayref->[ +1]; } ' Arrayref values: 24 and 101 Arrayref values: 25 and 102 Arrayref values: 23 and 103

    -- Ken

Re: foreach and lists
by Athanasius (Archbishop) on Mar 14, 2013 at 02:54 UTC

    The first element of the array @nametape is a reference to an anonymous array containing the elements 24 and 101. Note that a reference is a single, scalar value, not a list. On the first iteration of the foreach loop, $line is set to something like ARRAY(0x3cc154)). split finds no spaces to split on, so $values[0] contains ARRAY(0x3cc154) and there is no $values[1] (yet).

    I’m guessing that instead of split you want something like this:

    my @values = @$line;

    Do you have use strict; and use warnings; at the head of your script?

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: foreach and lists
by choroba (Cardinal) on Mar 14, 2013 at 09:38 UTC
    BTW, if you are already using prepare, use it with placeholders:
    $query = $dbh->prepare('INSERT INTO products_attributes (products_id, +options_id, options_values_id, options_values_price, price_prefix, pr +oducts_options_sort_order) VALUES (?, ?, ?, ?, ?, ?)'); $query->execute($products_id, $options_id, $options_values_id, $option +s_values_price, $price_prefix, $products_options_sort_order) or exit +1;
    See Exploits of a Mom.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      And of course once you have done that you will be able to move the prepare outside the loop while keeping the execute inside the loop. This is where a lot of the efficiency of prepared statement handles comes in.

      $query = $dbh->prepare('INSERT INTO products_attributes (products_id, +options_id, options_values_id, options_values_price, price_prefix, pr +oducts_options_sort_order) VALUES (?, ?, ?, ?, ?, ?)'); foreach $line (@nametape) { .... $query->execute($products_id, $options_id, $options_values_id, $op +tions_values_price, $price_prefix, $products_options_sort_order) or e +xit 1; }

      Think about other things such as the assignment of $options_id which could be moved outside the loop as well.

        Thank you everyone for your help, I now have my script working.