building a hash from a database
bfdi533
created: 2006-05-02 11:19:42

I am trying to build a hash depending on the in a database table that contains a 1 or 0 depending if there is data for a given element.

Given the following input table:

id    fname    lname
1     Joe      Smith
2     Sally    Smith

Here is the code I am using:

use DBI;
$dbh = DBI->connect("DBI:CSV:f_dir=./");
$query = "select id, fname, lname";
$sth->prepare($query);
$sth->execute();
while ($rowdata = $sth->fetchrow_hashref) {
    $hash{$rowdata->{'id'}} = $rowdata{'id'};
    if ($rowdata->{'fname'}) { $hash{$rowdata->{'id'}}{'fname'} = 1; }
    if ($rowdata->{'lname'}) { $hash{$rowdata->{'id'}}{'lname'} = 1; }
}

print Dumper(\%hash);

Yet, I do not get the expected results. I get the following:

$VAR1 = {
          '' => undef
        };

I would expect to see something like the following (constructed my myself and may or may not be valid):

$VAR1 = {
            {
              '' => 1
              'fname' => 'John'
              'lname' => 'Smith'
            {
            {
              '' => 2
              'fname' => 'Sally'
              'lname' => 'Smith'
            {
        };

Update: Changed all references to $rowdata{} to $rowdata->{}.

Re: building a hash from a database
zer
created: 2006-05-02 11:32:31
DBIx::Lookup::Field - Create a lookup hash from a database table
Re^2: building a hash from a database
created: 2006-05-02 11:35:41

That is not exactly what I am looking for. I need to basically create a has with each of the input columns indexed by id that has a 1 or 0 in the field depending on whether the database field is null or if it has data.

That code just facilitates repeated lookup on the database for a given input column.

Thanks for the reply, though.

Re: building a hash from a database
created: 2006-05-02 11:34:21
(update First of all, $rowdata contains a hashref, that's not the same as %rowdata. You have to use $rowdata->{'id'} instead of $rowdata{'id'}. And now, continuing with the rest of the story, assuming that is fixed...)

use strict;!!!

You're doing this in two steps. As a result of the line

$hash{$rowdata->{'id'}} = $rowdata->{'id'};
$hash{$rowdata->{'id'}} has an integer for a value, and you're using that as a symbolic reference to a new hash.

use strict would have prevented you from doing that.

I think you can change the code to do what you want, by changing that line to

$hash{$rowdata->{'id'}} = { '' => $rowdata->{'id'} };
Re^2: building a hash from a database
created: 2006-05-02 11:42:06

Hmmm... I must admit (if it is not obvious) that there a number of things about hashes that I do not understand.

What do you mean by symbolic reference to a new hash?

I have made the change that you suggested and now I get this:

$VAR1 = {
          '' => {
                  '' => undef
                }
        };

What I need to be able to do later is to reference the has created like this:

foreach $key (keys %hash) {
    print $key, $key{'fname'}, $key{'lname'}, "\n";
}
Re^3: building a hash from a database
created: 2006-05-02 11:44:39
You're still making the mistake of confusing $rowdata->{$field} with $rowdata{$field}. I fixed that in my code with an update, I admit I only spotted that later. So there was more than one thing wrong with the code. :)

What do you mean by symbolic reference to a new hash?
Well, first of all, you're setting the value of $hash{$id} to, say, 1. And then you set $hash{$id}{'fname'} to "foo". As a result, you really are trying to set $1{'fname'} to "foo".

What I need to be able to do later is to reference the has created like this:
foreach $key (keys %hash) { print $key, $key{'fname'}, $key{'lname'}, "\n"; }
No way, but you will be able to use
foreach $key (keys %hash) { 
    print $key, $hash{$key}{'fname'}, $hash{$key}{'lname'}, "\n"; }
Re^4: building a hash from a database
created: 2006-05-02 12:20:53

OK, ok, ok. I think I finally understand, finally.

I had tried that change from earlier and it did not make any difference at that time as I had not accounted for/changed the code to deal with the hashrefs correclty (->). I have now made both changes and it does exactly what I wanted it to.

I have learned much more about hashes than I realized I did not know.

Thanks (and thanks for the patience).

Re: building a hash from a database
created: 2006-05-02 11:35:21

You've used fetchrow_hashref but you're treating the value you get from it as if it were a hash rather than a hashref. Use $rowdata->{id} instead of $rowdata{id}. (Use -> everywhere you mention $rowdata) use strict would have caught this for you.

Re: building a hash from a database
created: 2006-05-02 11:44:17
fetchrow_hashref(), like the name suggests, returns a hash reference (i.e. a reference to a hash). You are accessing it as if it were a hash. As [bart] suggests, if you [id://111088], you would be aware of this error. Hash vs. hashref:
my %hash = (id => "123", fname => "Fred);
my $hashref = \%hash;

print "$hash{id}\n";
print "$hashref->{id}\n";
Re: building a hash from a database
created: 2006-05-02 12:10:21
How big of a CSV are we looking at here? If you have the memory, you could simplify with $sth->fetchall_arrarref({}) which would give you something like this:
$VAR1 = [
    {
        'id' => 1,
        'fname' => 'John',
        'lname' => 'Smith',
    },
    {
        'id' => 2,
        'fname' => 'Sally',
        'lname' => 'Smith',
    },
];
Then with your friend [map], you can massage this structure thusly:
my %hash = map { $_->{'id'} => $_ } @$data;
which would result in something along the lines of
$VAR2 = {
    '1' => {
            'id' => 1,
            'fname' => 'John',
            'lname' => 'Smith',
        },
    '2' => {
            'id' => 2,
            'fname' => 'Sally',
            'lname' => 'Smith',
        },
};

Ivan Heffner
Sr. Software Engineer, DAS Lead
WhitePages.com, Inc.

perlmonks.org content © perlmonks.org and bart, bfdi533, Codon, duff, runrig, zer

prlmnks.org © 2006 edmund von der burg (eccles & toad)

v 0.03