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

Hi, I'm trying to do the following in Perl. A dataset is being selected from a database using DBI/DBD. I need to be able to compare the current record with the previous record and depending on whether certain criteria are met either print the full current or partial current record. e.g.
$sth=$dbh->prepare("select data from mytable"); $sth->execute; while ($data = $sth->fetchrow_arrayref()) { if $data->[0],$data->[1],$data->[2] is the same as the equivalent elem +ents from previous record then print $data->[4] otherwise print complete $data record } $sth->finish; $dbh->disconnect;
This needs to be done in Perl not in the database select (I have no control over the select statement that is issued)
My knowledge of Perl is scant (but I'm learning !)
How do I do this ?
Any help appreciated

Replies are listed 'Best First'.
Re: compare current row with previous row
by davidrw (Prior) on Jan 16, 2006 at 14:42 UTC
    Just keep the previous row in another variable, and do the comparison you described..
    use Data::Dumper; my $prev_data; while (my $data = $sth->fetchrow_arrayref()) { if( $prev_data && $data->[0] == $prev_data->[0] && $data->[1] == $prev_data->[1] && $data->[2] == $prev_data->[2] ){ print $data->[4]; }else{ print Dumper $data; } $prev_data = $data; }
    Some issues, however:
    • Your sample select statement is only select'ing one column, but your code clearly expects at least 5.
    • Consider using fetchrow_hashref() instead for clarity (to the reader, ->[0] doesn't mean anything, but ->{last_name} does).
    • You may need to use the eq operator instead of == in some/all of your comparisons
    • There's probably a pure sql way to do whatever you're trying to do .... maybe something like (can't given exact sql w/o exact details):
      SELECT t.col0, t.col1, t.col2, t.col4 FROM mytable as t JOIN ( SELECT col0, col1, col2, min(col4) FROM mytable GROUP BY col0, col1, col2 HAVING COUNT(*) > 1 ) as tmp ON tmp.col0 = t.col0 AND tmp.col1 = t.col1 AND tmp.col2 = t.col2 AND tmp.col4 <> t.col4
      Update: I just noticed the note "I have no control over the select statement that is issued" .. why not? Is the prepare statement you listed not representative of your actual code?
      First off.. apologies for not stating the issue more clearly. This was my first post so in future I'll try and be more specific.
      The select statement I put in was purely as an example to demonstrate the issue. Granted I should have selected multiple columns. The real statement I'm dealing with is about a page of A4 and contains some pretty horrendous sql (imo). Anyhow suffice it to say the select being issued is fixed.
      The number of columns actually being selected is 15 but I'm only interested in a comparison of some of these columns.
      Thanks for the answer by the way
Re: compare current row with previous row
by holli (Abbot) on Jan 16, 2006 at 14:50 UTC
    That would be something along the lines of:
    my $prev; my $data; while ( $data = $sth->fetchrow_arrayref ) { conditional_print ($data, $prev); $prev = $data; } #repeat for last record conditional_print ($data, $prev); $sth->finish; $dbh->disconnect; sub conditional_print { my $data = shift; my $prev = shift; if ( $data->[0] eq $prev->[0] && $data->[1] eq $prev->[1] && $data->[2] eq $prev->[2] ) { print $data->[4], "\n"; } else { print join ("\t", @{$data}), "\n"; } }
    Basically you just have to remember the previous record somewhere.


    holli, /regexed monk/
Re: compare current row with previous row
by blazar (Canon) on Jan 16, 2006 at 15:11 UTC
    #!/usr/bin/perl -l use strict; use warnings; my @old=split ' ', <DATA>; print "@old"; while (<DATA>) { my @cur=split; print "@cur[0,1]" eq "@old[0,1]" ? $cur[2] : "@cur"; @old=@cur; } __END__ foo bar baz foo fred baz foo fred burz bar baz burp

    Additional checks and adaptation to current situation are left as an exercise to the reader.

    Although it should be clear that this is meant as a minimal example, I'd like to stress that "@cur[0,1]" eq "@old[0,1]" is a simple minded equality test based on joining on $", which happens to be a space by default. Of course this works here, but is bound to be unreliable in a realistic situation, and you may have to roll a more sophisticated test yourself.