Avant-propos

Une question souvent posée sur les forums Delphi concerne la réalisation de la somme des champs d'une grille de données (TDBGrid). Dans l'exemple courant de la réalisation d'un programme de facturation, on voudrait pouvoir afficher facilement le total de la facture X pour le client Y.

Image non disponible

Plusieurs solutions existent pour arriver à ce résultat. Au niveau programmation, la plus efficace est certainement l'utilisation des TAggregateField proposés par la version Pro de Delphi.

I. Solutions diverses

Voici 3 solutions possibles pour arriver à nos fins !
Les deux premières solutions exploitent l'événement OnStateChange du composant TDataSource fournissant les données à la grille. La troisième utilise les aggrégats maintenus.

I-1. Solution 1

La première solution consiste à désolidariser la grille de données de la table des données par le méthode Table.DisableControls. On place ensuite un bookmark sur l'enregistrement en cours, puis on positionne le curseur sur le premier champ de la table. On balaye la table jusqu'au dernier enregistrement en additionnant les valeurs du champ dont on veut trouver la somme. Enfin on se repositionne sur le Bookmark défini précédemment et on réactive la grille de données avec la méthode Table.EnableControls. Tout cela est un rien compliqué, et gourmand en temps de traitement. Cette solution ne sera pas utilisable sur une grande quantité de lignes de données.

I-2. Solution 2

La seconde solution utilisera un TQuery pour calculer et afficher au moment voulu la somme des valeurs concernées. On utilisera alors une requète comme celle-ci:

 
Sélectionnez
SELECT SUM(MontantLigne) FROM LignesFactures WHERE Facture = :Numero

Le paramètre :Numero étant le numéro de la facture en cours de traitement. Là encore, même si le traitement par SQL est plus rapide, la solution impose certaines contraintes. Par exemple, on doit vérifier avant chaque calcul que le Datasource fournissant les données ne soit pas en mode dsEdit ou dsInsert pour ne pas fausser les calculs.

I-3. Solution 3 : les aggrégats

Dans les versions D5 Entreprise puis D6 Pro de Delphi, Borland nous a fournit des composants permettant de faciliter la manipulation de ces données: TClientDataset et TAggregateField. Ce dernier gère ce qu'on appelle un aggrégat maintenu.

II. Qu'est-ce qu'un aggrégat maintenu ?

Un aggrégat maintenu est un résumé de données automatiquement mis à jour au fur et à mesure que sont modifiées les données dans l'ensemble de données. Le résumé le plus simple sera la somme de toutes les valeurs d'une colonne d'une table de données, mais d'autres types de résumés sont permis. Voici ces types de résumés dans un extrait de l'aide Borland.

Opérateur Rôle
Sum : Somme des valeurs d'un champ numérique ou d'une expression
Avg : Valeur moyenne d'un champ numérique ou date/heure ou d'une expression
Count : Spécification du nombre de valeurs exprimées pour un champ ou pour une expression
Min : Valeur minimale d'un champ chaîne, numérique ou date/heure ou d'une expression
Max : Valeur maximale d'un champ chaîne, numérique ou date/heure ou d'une expression

Ces aggrégats vont donc nous permettre de multiples choses.

III. Création d'un aggrégat

Un champ de type TAggregateField se crèe dans un TClientDataset, fourni seulement avec la version Pro de Delphi. Rappelons qu'un TClientDataSet est un composant orienté données qui conserve l'ensemble des enregistrements créés soit directement, soit provenant d'une source de données quelconque" (certains composants orientés données sont dit de type unidirectionnel car justement ils n'ont pas cette capacité de bufferisation).

Image non disponible

Pour créer un TAggregateField, on utilise l'éditeur de champs du composant TClientDataset, exactement comme pour ajouter un champ du Dataset source ou pour créer un champ calculé.

Image non disponible

Le type choisi est aggrégat, et le type de champ statistiques. La validation de la boite de dialogue de création de champ ajoute le champ créé dans la zone inférieure de l'éditeur.

Image non disponible

Une fois le champ créé, on va pouvoir définir le calcul qu'il devra réaliser pour nous grâce à la propriété Expression du composant. Par exemple:

 
Sélectionnez
Expression := 'SUM(Quantite * PrixUnitaire)';

nous fournira le résumé (constamment mis à jour) définissant le total des lignes calculées de notre facture. Les propriétés les plus importantes de TAggregateField proposées par l'explorateur d'objet sont les suivantes:

Image non disponible

L'importance de GroupingLevel

Une propriété très importante du composant TAggregateField est la propriété GroupingLevel qui, comme son nom l'indique, permet des regroupements de données selon certains niveaux. Prenons l'exemple d'une table Lignes qui contient toutes les lignes de toutes les factures de la base. Chaque ligne est rattachée à une facture par un numéro. En utilisant un index basé sur ce numéro, on peut définir:

 
Sélectionnez

GroupingLevel := 0; // Pour afficher le résumé de toutes les lignes de la table
GroupingLevel := 1; // Pour obtenir le résumé sur le champ indexé Numero.

Nous verrons cela plus en détail dans l'exemple suivant.

IV. Les aggrégats par l'exemple

Pour illustrer ce document, je vous propose la réalisation pas à pas d'une gestion (simplifiée) de factures. A la fin de cet exercice, vous serez à même de réaliser des applications utilisant les aggrégats avec Delphi.

Vous êtes prèt ? Alors, en route pour le Tutoriel.