Perl

Supposons que nous ayons une base de données Postgresql, une table activite qui contient, entre autre:

  • jour: une date au format jj/mm/aaaa
  • duree: une durée en heures
  • projet: l'identifiant d'un projet éventuellement nul
  • personne: l'identifiant d'une personne

Cette table permettant de relever l'activité des personnes sur des projets doit être utilisée pour fournir un récapitulatif du total des heures par mois et par personnes depuis un script Perl utilisant DBIx::Class.

Il faut donc faire une requête des lignes ayant une référence projet, en transformant la date du jour au format mmaaaa et en les regroupant par date toujours au format mmaaaa, par personnel et par projet. Simple ! Donc voici:

my @heures = $db->resultset('Activite')->search({
 '-and' => [
   jour =>   { '>=', $debut },
   jour =>   { '<=', $fin   },
 ],
 'projet.id_ref' => { '!=', undef },
},{
 select =>   [ 
   'projet', { SUM => 'duree' }, \"to_char(jour, 'MMYYYY')", 
   'personne' 
 ],
 +as     =>   qw/projet duree mois personne/,
 group_by => qw/mois personne projet/,
 order_by => qw/projet jour personne/,
 join =>     'projet',
})->all();

Précisons que $debut et $fin sont les dates entre lesquelles on veut effectuer la recherche.

Explication: on recherche les lignes entre $debut et $fin ayant une référence projet et on récupère le projet, la somme des durées, la date transformée au format mmaaaa et la référence des personnes. On appelle mois la date transformée au format mmaaaa et on fait un group by sur ce nouveau champ.

Je précise également que les projets et les personnes sont enregistrées dans des tables auxquelles les champs éponymes font référence.

Mais ça ne fonctionne pas car avec DBIx::Class, le group by n'utilise pas la version transformée de mois mais celle du champ source jour. On obtient donc une ligne par jour, par projet et par personne au lieu d'une ligne par mois, par projet et par personnel.

La solution consiste à reporter dans Group By la même expression de transformation que dans le Select. Voici une version qui fonctionne:

my @heures = $db->resultset('Activite')->search({
 '-and' => [ 
   jour =>   { '>=', $debut },
   jour =>   { '<=', $fin   },
 ],
 'projet.id_ref' => { '!=', undef },
},{
 select =>   [ 
   'projet', { SUM => 'duree' }, \"to_char(jour, 'MMYYYY')", 'personne' 
 ],
 +as     =>   qw/projet duree mois personne/,
 group_by => [
   \"to_char(jour, 'MMYYYY')", 'personne', 'projet' 
 ],
 order_by => [ 
   \"to_char(jour, 'MMYYYY')", 'projet', 'personne' 
 ],
 join =>     'projet',
})->all();