Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Finer points of Class::DBI

by rlb3 (Deacon)
on Sep 13, 2004 at 21:50 UTC ( [id://390671]=perlquestion: print w/replies, xml ) Need Help??

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

Hello Monks, For the last couple of months I have been trying to understand the Class::DBI module.
Slowly I've started to use it in some of my projects. The problem I'm having is
learning the finer points of the module. For example, lets say I have a database
with two tables. The first table Areas has a has_many relationship with the Stats
table. Now for the project I want to create a report with all the stats organized
by Areas. So the code would look something like:
my @areas = Areas->retrieve_all; foreach my $area (@areas) { print $area->name.":\n"; foreach my $stat ($area->stats) { print "\t".join ",", ($stat->name,$stat->disk,$stat->m +onth)."\n"; } }
This would print out something like:
IT: Robert,200mb,8 Lewis,100mb,5
Well thats all fine and good unless I want only the stats from August(8).
I'm not sure how to do this without grabing all the stats for an area then using
something like grep to get only the stats I want. I'm sure there is a better way to
do it, but I'm just not seeing it.

Any help would be great.

rlb3

Replies are listed 'Best First'.
Re: Finer points of Class::DBI
by cleverett (Friar) on Sep 13, 2004 at 22:37 UTC
    Try something like:
    foreach my $area (Areas->retrieve_all()) { my $stats = $area->stats(month => 8); print join(', ', $area->name, $stat.name, $stat->disk, $stat->month), "\n"; }
    HTH
      print join(', ', $area->name, $stat.name, $stat->disk,

      Perhaps you mean $stat->name instead of $stat.name?

        Heh, been spending too much time with Template Toolkit.
Re: Finer points of Class::DBI
by eric256 (Parson) on Sep 13, 2004 at 22:45 UTC

    Under the has_a and has_many sections of the docs, there is one called limit, which explains how to get results that are limited.


    ___________
    Eric Hodges
      You have not mentioned what is your database. If it is a RDBMS, then you could join the tables and order by areas. It will be much more simple and faster.

        Yeah, some more details on the db architecture would be very useful since this seems like more of a query issue than anything else.

        While I can envision a number of ways that an area would have a 1..n relationship with the statistics, I'm just going to have to guess at the field layout (note, I'm not even getting into normalisation):

        --------------------  --------------------
        | Areas            |  | Stats            |
        --------------------  --------------------
        | PersonId         |  | PersonId         |
        | Person           |  | Person           |
        | Group            |  | Stat             |
        --------------------  | MonthKey         |
                              --------------------
        

        Assuming that your setup looks anything like this, then there are several ways to query this table for an ordered list of stats.

        If you wanted everything ordered by date (so no rollup) it would be:

        SELECT monthKey, group, person, stat FROM areas a, stats s WHERE a.personId=s.personId ORDER BY monthKey, group, person, stat ;

        If you wanted to get a date range it would be:

        SELECT monthKey, group, person, stat FROM areas a, stats s WHERE a.personId=s.personId AND s.monthKey > 200401 AND s.monthKey < 200406 ORDER BY monthKey, group, person, stat ;

        And so on.

        The output from this query would be quite easy to work with in Perl because you can run through the output without worrying about order:

        my $sth = $dbh->prepare($query); $sth->execute(); my $current_month; my $current_group; my $current_person; while (my $rv = $sth->fetchrow_arrayref()); if ($rv[0] ne $current_monthkey) { # print out new month header $current_month = $rv[0]; undef $current_group; undef $current_person; } if ($rv[1] ne $current_group) { # print out new group header $current_group = $rv[0]; undef $current_person; } if ($rv[2] ne $current_person) { # print out new person header $current_person = $rv[1]; } # print out stat } $sth->finish(); $dbh->disconnect();

        Hope that helps -- it was a bit of a speculative jump based on the available information, but dbs are designed for querying, sorting, and ordering in clever ways that require you to be a true programming god to reproduce in Perl with anything like comparable performance.

        Then he'd have to use Data::Grouper, or something like that to build his hierarchical format. Yes, using CDBI results in N+1 queries to the RDBMS, where N = the number of records returned by the initial Areas->retrieve_all(). However, the real glory of CDBI has to do with the amazing code reduction it achieves (especially in conjuction with Template Toolkit for example), not the performance.

        Moral: use CDBI where reusability, portability and ease of coding take a priority over performance (almost everywhere). Use hand coded SQL and DBI when you need to sacrifice everything for speed.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://390671]
Approved by Ovid
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others rifling through the Monastery: (4)
As of 2024-04-19 22:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found