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

hello, today I'm afflicted with a problem I'm finding hard to grasp and i hope that the more expert will be able to guide me.
basically i need to pull out data from a database and based on comparisons update fields in the db. in principle it sounds simple, but I'm struggling with the code and possibly the logic...
if it was for a few rows i thought that i could execute the query and pas the values to an array, then manipulate the array, however for thousands of columns this might not be the most efficient way (please argue against this if i'm wrong!)
a different way is to pull out values in chunks of rows, but if you look at the example below i don't have any way of checking in advance how many rows contain invalid chars.
here is an example myTable containing:
Field1, Field2, Field3, Field4 ....
100, abc, 4
100, -, 3
105, -, 5
105, -, 5
105, def, 3
101, fgh, 4
101, -, 4
....etc.

what i thought would be more efficient is to take one row at a time and compare the content with the one above and the one below (or row+i if the value returned is still invalid), but have no clue how to keep the loop clean.
here is my pseudo-code:

- create connection,
- execute query to get no of rows (i)

start loop
- execute query for row i,
get rowi.field1
get rowi.field2

if rowi.field2 = '-' then
get rowi.field1
if rowi.field1 = rowi-1.field1 then
rowi.field2=rowi-1.field2
elseif rowi.field1 = rowi+1.field1 then
rowi.field2=rowi+1.field2
else
loop until find a valid entry and use
rowi+x.field2
end if

i also need a count of the consecutive
rowi.field1 which are equal
i hope that somebody can suggest a good solution and thank you for your help! thanks

Replies are listed 'Best First'.
Re: DBI efficient loop?
by Corion (Patriarch) on Jun 10, 2008 at 18:13 UTC

    I don't understand your data manipulation requirements. It would be better if you edit your post to put your code in between <code>...</code> tags.

    I think you could save a lot of work by pushing the data manipulation into the database instead of running a loop in Perl to do the data manipulation. If you need the count of FIELD1 that are equal, that's just some basic SQL:

    select field1, count(*) from mytable group by field1

    Your other query seems to have some more convoluted logic, but if you can reformulate it in a more descriptive than prescriptive way, it will be translatable to SQL far more easy. You use vocabulary like "loop until find a valid entry", which I guess means "not equal to '-'". My guess at it is the following, but I'm unclear on whether you want to actually manipulate the data or just return a result:

    select field1 from mytable l where field2 <> '-' order by field1, field2

    or, if you only want all the "first" rows of field1 where field2 is not '-', then maybe the following returns what you need:

    select field1, min(field2) from mytable l where field2 <> '-' group by field1 order by field1, field2
      hi guys, thanks for the replies. i still haven't solved the issue, but you made me think about using an hybrid solution.
      i thought about using mysql directly to manipulate fields, however it is possible that my knowledge/experience of mysql is just not good enough!
      i can't take a blanket query like the one suggested as records are chronological and depend on each other.
      filtering out all rows with a field2 containing '-' is not good enough as i need to substitute the value with a 'real' string which is extracted comparing field1 in either the previous or next row if the values in field 1 are the same.(if anyone has suggestions please pass them on!)
      however it was very useful to consider your suggestion to consider the query with min(fieldX) as i queried all the single entries matching entries with a 'real' value.
      select pKey, field1, min(field2) from myTable where field2 <> '-' and pKey<20000 group by field1 order by pKey,field2
      what i thought after this is that i can pass the values to a much smaller 'reference' array and use another pass to check rows with the reference and substitute where necessary.
      something i still have issues in grasping where is ideal to prepare and execute the queries in the loop, therefore suggestions will be much appreciated!
Re: DBI efficient loop?
by ralife (Novice) on Jun 10, 2008 at 18:13 UTC
    Hello, I am currently using DBI to connect to an MS Access DB and I find it very easy to use the hash_ref rather than an array because you can then pull any field with the name rather than having to use indexes. Some code to demonstrate I’ll assume you already connected to your database:
    $dbi_dsn = "dbi:ODBC:<Name of Database>"; ############################# # connect to database $dbh = DBI->connect($dbi_dsn) or die "Can't connect to $dbi_dsn: $DB +I::errstr"; $sth = $dbh->prepare(“Call you query here”); $sth->execute(); while ($hash_ref = $sth->fetchrow_hashref) { $field_1_value = $hash_ref->{Field1}; ... $field_4_value = $hash_ref->{Field4}; }
    So now your in a while loop and depending on the name of each field you can access it by calling $hash_ref->{NAME_OF_FIELD} and it loops through the entire table. Hope this helps.