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

I have a question concerning pulling an alternate field entry from a flat database. Currently, the program below is set to pull the first field from the pipe delineated DB, but I would like to pull the 8th field. How can I accomplish this?
open DATA,$data; $line=<DATA>; @fields=split('\|',substr($line,0,index($line,";"))); %data=(); while (<DATA>) { my(@flds)=@fields; shift(@flds); my(@temp)=split('\|',substr($_,0,index($_,";"))); my($id)=shift(@temp); while ($#flds>-1) { if ($temp[0] eq "no") { $temp[0]=""; } $data{$id}{shift(@flds)}=shift(@temp); } } close DATA; print "Content-type: text/html\n\n"; open TMPL,$catalog; while (<TMPL>) { $line=$_; chop($line); while ($line=~/^(.*?)<!thumb=(.*?)>(.*)$/) { print $1; $id=$2; $line=$3; if ($data{$id}{'thumb'} ne "") { print "<a href=$show_url?database=database&action=view_product +&productID=$2&category=$data{$id}{'Category'}>\n"; print "<img src=${thumb_src}$data{$id}{'thumb'} border=$border + hspace=0 vspace=0 alt='$alt_text $data{$id}{'Name'}' height=65 width +=65></a>"; } if ($data{$id}{'Name'} ne "") { print "<br><font face='$font_face' size=$font_size><SMALL> $da +ta{$id}{'Name'}<BR></SMALL></FONT><font color=red size=+1>"; print '$', "\n"; print "$data{$id}{'Price'}"; } } print $line,"\n"; } close TMPL;
Thank you so much for any assistance you can give.

Edit kudra, 2001-09-05 Elaborated on subject which was 'Database question'

  • Comment on Database question: pulling a particular field from a flat database
  • Download Code

Replies are listed 'Best First'.
Re: Database question: pulling a particular field from a flat database
by foogod (Friar) on Sep 05, 2001 at 19:02 UTC

    why not something like this:

    #!perl use strict; my $file = "foo.txt"; open (FH, "$file") || die ("unable to open the file!: $!"); my @ODB = <FH>; close (FH); my $line; foreach $line (@ODB) { my ($field1,$field2,$field3,$field4,$field5,$field6,$field7,$field8)=s +plit('\|',$line); my ($field_data,$comment)=split(";",$field8); print "$field_data\n"; }
    this is assuming a data file like:
    field1data|field2data|field3data|field4data|field5data|field6data|fiel +d7data|field8data1; comment goes here!

    HTH

    - f o o g o d --- ruining the bell curve for everyone else ---

      Maintainability notes:
      1. Include the name of the file in the error message. Just knowing that you failed because , "No such file or directory" is not nearly as useful as knowing which file purportedly does not exist.
      2. Why put the lines into an array? It is just as easy to read from the file directly, and that gives you the option of reading it incrementally with a while loop. (Huge improvement on large files.)
      3. Indentation?
      4. You forgot to chomp the lines from the file.
      5. I find that using a hash slice rather than a list of variables is much more maintainable. That way minor (or major) data format changes are much easier to handle.
      With those changes this example would become something like:
      #! perl use strict; my $file = shift(@ARGV) || "foo.txt"; open(FH, $file) or die("Cannot read '$file': $!"); my @field_list = qw(put in reasonable names here for your data); while (<FH>) { chomp; my %row; @row{@field_list} = split /\|/, $_; my ($field_data, $comment) = split /;/, $row{data}; print "$field_data\n"; }
      Of course the original author should switch to a data format which is self-documenting (for instance make the first line a header line that says what fields are in use). And when you do that, the use of a hash slice makes things very easy - just read the list of field names out of the header line!

        Everything you said above is right on the money. The hash slice approach is much "smarter" ... sometimes I have to dumb down things for my coworkers ... and then it gets hard for me to use both halves of the old brain.

        Thanks for the reply ... I will be sure to take a breath before I start spouting off code next time.

        thanks,

        - f o o g o d

Re: Database question: pulling a particular field from a flat database
by monkfish (Pilgrim) on Sep 05, 2001 at 18:42 UTC
    It would have been helpful to include sample data, but from the code I conclude it looks like this:
    fieldname1|fieldname2|fieldname3|fieldname4|fieldname5|fieldname6|fiel +dname7|fieldname8; Comment id1|val2|val3|val4|val5|val6|val7|val8; another comment no|val2b|val3b|val4b|val5b|val6b|val7b|val8b; another comment id1c|val2c|val3c|val4c|val5c|val6c|val7c|val8c; another comment

    Is this correct?

    The code is pulling all the fields. Rather than reference it by number, what is the name of the 8th field that you want?

    -monkfish (the fishy monk)

      Sorry I didn't include the db example:
      ID|Category|Name|Image|Description|Price|Taxable|thumb|Listing
      Currently, the first part of the script, shown below, only looks for the first field in the database, or in this case the "ID" field. I want it instead to use the Listing field.
      open DATA,$data; $line=<DATA>; @fields=split('\|',substr($line,0,index($line,";"))); %data=(); while (<DATA>) { my(@flds)=@fields; shift(@flds); my(@temp)=split('\|',substr($_,0,index($_,";"))); my($id)=shift(@temp); while ($#flds>-1) { if ($temp[0] eq "no") { $temp[0]=""; } $data{$id}{shift(@flds)}=shift(@temp); } } close DATA;
      Thanks
        Do you want the id (by which you reference things later on in the script) to be the listing? If that is really the case then just change:

        my($id)=shift(@temp);

        to

        my($id)=$temp[7];

        This however may have other unwanted results in the code since @temp will now have one more element than it did before (since you didn't shift any thing off). You could change all of your shifts to pops and that should do what you want.

        If, however, what you are really concerned with is a display issue in the template below, then you'll want to do something like using: $data{$id}{'Listing'} in the display and leave the code alone.

        Does that help?

        -monkfish (the fishy monk)

Elaboration on my Database question
by koacamper (Acolyte) on Sep 05, 2001 at 18:37 UTC
    The database that I am working with looks something like this:
    ID|Category|Name|Image|Description|Price|Taxable|thumb|Listing
    The first part of the script, shown below, looks through the db for the first field, or in this case, "ID" field. I want the first part of this script to use the "Listing" field instead of the "ID" field.
    open DATA,$data; $line=<DATA>; @fields=split('\|',substr($line,0,index($line,";"))); %data=(); while (<DATA>) { my(@flds)=@fields; shift(@flds); my(@temp)=split('\|',substr($_,0,index($_,";"))); my($id)=shift(@temp); while ($#flds>-1) { if ($temp[0] eq "no") { $temp[0]=""; } $data{$id}{shift(@flds)}=shift(@temp); } } close DATA;
      You are splitting the data into an array. You have already told us that you know the field you want is the eighth. You can access any element of the array you want via $foo[n] where n is the index of the field you want. Since arrays start counting at 0 ( normally at least, it can be changed but I am going to assume you haven't ), the eigth element can be gotten at index 7 --
       my $id = $temp[7].

      Is that enough?