tags:

views:

306

answers:

6

I am required to pull out rows corresponding to column name. The rows being pulled out correspond to address in array @values. Following is my code:

use strict;
use DBI;

open (FH, "/user/address") or die $!;
my@values=<FH>;
close(FH);
my @names;

my $query = "Select name from table where address = ?";
my $sth = $dbh->prepare( $query ) or die "could not prepare statement\n", $dbh->errstr;
foreach my $value(@values){ #@values contain list of address
        $sth->execute($value) or die "could not execute statement $query\n", $sth->errstr;
        while ($result = $sth->fetchrow_hashref()){
               my $name_reqd = $result->{name};
               print "Name Req: $name_reqd\n"; #not printing anything 
               push (@names, $name_reqd);
        }
}
print "@names\n"; #not printing anything

But when I print @names, I don't get any output, I am unsure as to what is going wrong.

A: 

Is your table really called "table"? Maybe it should be $table, with $table set to the actual name of the table.

If you can, for example SQLite or MySQL have this, try running your query from the database command line.

Kinopiko
no, i wrote it to generalize. But does that matter?
tinker
Don't post non-answer answers.
Sinan Ünür
This seems to me to be a valid answer. It's not the correct answer but I don't see how it is invalid or not an answer. It's perfectly possible that he'd forgotten the dollar sign.
Kinopiko
+1  A: 

untested, but shouldn't you access your fields like this.

my $name_reqd = $result[0];

This is because you are using fetchrow_array().

bichonfrise74
+1 The OP first had `fetchrow_array()` in his post before he edited it. So the downvote on this post was not deserved.
Sinan Ünür
+1  A: 

You should ensure that the database driver is returning column names in lower case. Also, use selectcol_arrayref for this type of query:

use strict;
use warnings;

use DBI;
use File::Slurp;

my @values = read_file '/user/address';
chomp @values;

my $dbh = DBI->connect(
    # appropriate parameters
);

my $sth = $dbh->prepare(
    'SELECT name FROM table WHERE address = ?'
) or die sprintf 'Cannot prepare: %s', $dbh->errstr;

my @names;

for my $value ( @values ) {
    my $names = $dbh->selectcol_arrayref(
        $sth,  {},  $value
    ) or die sprintf 'Cannot select col: %s',  $dbh->errstr;

    push @names,  @$names;
    print "'$_'\n" for @$names;
);

print "@names\n";
Sinan Ünür
Considering you told me not to post non-answers, what on earth do you mean by this? The syntax of tinker's question is correct, you are simply giving a different way to achieve the same result, and not even answering the question.
Kinopiko
Going by the documentation, selectcol_arrayref combines prepare and execute. I dont think that is the problem I am facing. My prepare and execute statements work. the issue is either with the '$result' part or the while loop.
tinker
@Kinopiko: A question such as *Is the name of the table really table?* is a non-answer.
Sinan Ünür
@Sinan: Your code will most probably work. But, I am interested in knowing what is wrong with my code? Why is not printing anything? Thanks!
tinker
I *think* adding a `print Dumper $result;` in the body of the `while` loop will reveal the answer.
Sinan Ünür
@Kinopiko Because you keep posting those non-answer answers which should rightly be comments, you keep taking away the opportunity to earn additional badges for others and creating pressure to post quickly. The point is `selectcol_arrayref` does not depend the database driver returning keys in lower case, but I did not get a chance to write out my post because your non-answer answer popped up as I was typing my answer. So, post-edit-post-edit was how I responded to it.
Sinan Ünür
So my rapid answer "forced" you to write your answer quickly. I'm very sorry about that. I'll try not to answer questions so quickly next time.
Kinopiko
+4  A: 

The problem with this code is file reading. Code my @values=<FH>; reads all lines with new-line (\n) symbol at the end. It should be manually removed in this case. You can do it using chomp function:

open (FH, "/user/address") or die $!;
my @values = <FH>;
chomp(@values);
close(FH);

Update: I think it's not searching anything because it just can't find. Addresses usually have spaces within. Query Select name from table where address = ? will find only exact equal addresses (letter case is the only thing ignored). For example " a" is not equal to "a" in sql.

Ivan Nevostruev
It isn't 100% but that looks likely.
Kinopiko
@Ivan: nope, adding chomp does not help.
tinker
Do you mean after the while loop? $result has no value/defination before while loop.
tinker
@tinker: yes after loop... it will show you values of variables, which can be usefull to undestand what's happening. But the code looks good so far. I think it's not searching anything because it just can't find. Addresses usually have spaces within. Query `Select name from table where address = ?` will find only exact equal addresses (letter case is the only thing ignored). For example " a" is not equal to "a" in sql.
Ivan Nevostruev
So why did you accept this answer if it did not help?
Ether
"I think it's not searching anything because it just can't find. Addresses usually have spaces within. " of Ivan answer helped.
tinker
I've added that comment as part of answer
Ivan Nevostruev
+1  A: 

DBI performs case conversion on column names, so it may be returing the result in the key "NAME" instead of "name".

What do you see if you print keys %$result after calling $sth->fetchrow_hashref ?

mobrule
does not print any thing (just a new line).
tinker
+4  A: 

I see a few things:

  • you aren't declaring @names before you use it, which means it is being automatically declared at the scope of its first use: inside the while loop. Moreover a new copy is destroyed and created on every iteration of the loop, and then a new (empty) one is created when you call print. Adding use warnings; would catch this.
  • (as mobrule and others have said) you may not be accessing the data correctly out of $result. Try adding use Data::Dumper; print Dumper($result); in the top line of the while loop to see what data you have read in.
  • I'm not sure what format you are using in /usr/address, but if it has more than one line, you're only reading the first line from that file. You can read in the entire file in one go by localizing $/ first (see perldoc perlvar). Moreover (as Ivan said), this string will still have a newline at the end: use chomp to strip it (perhaps after splitting into lines, if you slurped more than one). See perldoc -f chomp and perldoc -f split.

Between these points, you should have enough debugging data being printed that you should easily see where you went wrong.

Ether
printing $result before while loop, print : $VAR1=undef;
tinker
@Ether +1 for summarizing useful debugging ideas. @tinker I am giving up on you: I do not think the code you are showing us is actually the code that exhibits the problem. Or, your input does not match what's in the database. Either way, we do not have real information that can help us give real answers. Voting to close your question as a not a real question.
Sinan Ünür
@tinker: you're dumping `$result` before it has either been declared or assigned? No wonder it's empty. Try dumping it just after you assign it in the while loop, perhaps?
Ether