in reply to building an HoAoH ... very badly

If you you can fetch the data ordered (as your example suggests), you do not mind having extra keys in the episode hashrefs, and you know that your seasons run from first to n-th, you could fetch like this:
my $appearances = []; while ( my $ref = $sth->fetchrow_hashref() ) { my $season = $ref->{season}; unless ( exists $appearances->[$season -1 ] ) { $appearances->[$season -1 ] = { season => $season, eps => [] }; } my $eps = $appearances->[$season -1 ]->{eps}; push @$eps, $ref; }
This should give you
$appearances = [ {season => 1, eps => [ {season => 1, ep => 1, title => 'Hellmouth' }, ......
Disclaimer: untested

Update: Note that since this code recycles the hashref from DBI, if you add more fields in your SQL later, they will show up in the final data structure as well.