[Dbix-class] Joining for counts of related items.

Rob Kinyon rob.kinyon at gmail.com
Sat Apr 24 14:14:23 GMT 2010


On Fri, Apr 23, 2010 at 18:09, Bill Moseley <moseley at hank.org> wrote:
> Back to my Music database.  In my Cd class I have these methods to return
> counts of tracks of a specific type.
>
> sub foo_track_type_count {
>     return shift->tracks( { track_type => 1 } )->count;  # any different
> then count_related??
> }
> sub bar_track_type_count {
>    return shift->tracks( { track_type => { -in => [2,3] } } )->count;
> }
>
> Now, it turns out that I always need these counts.
> $cd => $schema->resultset( 'Cd' )->find( $id );  # one database select
> my $foos = $cd->foo_track_count;  # second select
> my $bars = $cd->bar_track_count;  # third.
>
> I know I can build a resultset that includes a total count (as seen in the
> Cookbook), but is there a way to include counts that are limited to those
> specific "track_types"?
> IIRC from past discussions this had to be done with a custom FROM which then
> broke some other functionality.

The question you should always ask yourself is "How would I do this in
raw SQL?". The answer is "With a subquery in my SELECT clause." The
raw SQL would look something like:

SELECT me.id, me.name,
    ( SELECT COUNT(*) FROM tracks WHERE tracks.cd_id = me.id AND
track_type IN ( 1 ) ) AS foo_track_count,
    ( SELECT COUNT(*) FROM tracks WHERE tracks.cd_id = me.id AND
track_type IN ( 2, 3 ) ) AS bar_track_count,
  FROM cds AS me
 WHERE me.id = ?

Given that, it should seem pretty obvious that proper solution should
have correlated subqueries in a +select. The rest is left as an
exercise to the reader.

Rob



More information about the DBIx-Class mailing list