tags:

views:

384

answers:

3

The following code seems to be just too much, for getting a single count value. Is there a better, recommended way to fetch a single COUNT value using plain DBI?

sub get_count {
   my $sth = $dbh->prepare("SELECT COUNT(*) FROM table WHERE...");
   $sth->execute( @params );
   my $($count) = $sth->fetchrow_array;
   $sth->finish;

   return $count;
}

This is shorter, but I still have two statements.

sub get_count_2 {
   my $ar = $dbh->selectall_arrayref("SELECT ...", undef, @params)
   return $ar->[0][0];
}
+2  A: 

I don't know Perl, but if it's syntax is logical I would think this would work based on your 2nd example:

sub get_count {
   return $dbh->selectall_arrayref("SELECT ...", undef, @params)->[0][0];
}
Tony Andrews
Good guess for someone who doesn't know Perl. :)
friedo
nice, though it should be $dbh->selectall_arrayref("SELECT ...", undef, @params)->[0][0]; as the call returns a matrix and not a vector. (I had the same mistake in my original example but I fixed it since your comment)
szabgab
OK, fixed that.
Tony Andrews
+6  A: 

Easy enough to do in one line with no extra variables:

$count = $dbh->selectrow_array('SELECT count(*) FROM table WHERE...', undef, @params);
Dave Sherohman
That'd be my solution too.
MarkR
That's what I was looking for. Thanks!
szabgab
A: 

I probably wouldn't do this myself, but you could always make it a new top-level function of the DBH object you're using:

WARNING: untested code follows!

sub DBD::SQLite::db::count
{
   my($dbh, $table, $where) = @_;

   my($stmt) = "SELECT COUNT(*) FROM $table";
   $stmt .= " WHERE $where" if $where;

   my($count) = $dbh->selectrow_array($stmt);

   return $count;

}

and then call it like this:

my($cnt) = $dbh->count('Employee', 'year_hired < 2000');

Besides polluting a namespace that's not yours, you'd also have to write this for every DB driver you use, though I'm sure your could work something up that allows you to construct and eval some code to auto-configure this for a given DBH object.

Joe Casadonte
Aside from polluting someone else's namespace and needing to rewrite it for every DBD you use, the solution as presented requires you to interpolate values into the SQL string instead of losing placeholders ('year_hired < ?'), so you lose access to the best possible protection against SQL injection attacks.
Dave Sherohman
Good point; the main thrust of this, though, was in response to the OP's comment "If I had a built-in statement for that in DBI".
Joe Casadonte