Faire un cumul avec Reporting Services
Par Djeepy1 le samedi 16 février 2008, 15:17 - Business Intelligence - Lien permanent
Erratum :
J'étais fatigué (retour de TechDays ??) quand j'ai écrit cet article car il y a une solution beaucoup plus simple (que je connaissais en plus). Je n'ai pas voulu écouter la petite voix dans ma tête qui me disait "abruti, abruti" quand j'ai cité la fonction Previous. Bref, la solution est :
=RunningValue(Fields!SubTotal.Value, Sum,
Nothing)
Mais je vous invite à lire la solution proposée ci-dessous car elle est utile pour de aggrégats un peu custom (et puis pour dire que je n'ai pas gratté pour rien).
Article Original
Dans cet article nous allons voir comment faire une somme cumulée dans un rapport. Le principe est simple, j'ai des ventes dans le temps et pour chaque date, je veux le cumul depuis la première date.
Reporting Services n'offre pas cette fonctionnalité en natif mais nous allons mettre en place les élements pour le suporter. Sans vouloir gâcher la surprise, je peux déjà vous annoncer que l'on va passer par du code .NET ajouté au rapport.
Pour commencer, voyons ce que nous offre Reporting Services comme fonction en rapport avec notre besoin. Il y a la fonction Previous qui permet de récupérer des données dans la ligne précédente. Cependant, cela ne marche plus à partir de la 3eme ligne car la fonction ne remonte pas plus haut.
L'idée pour résoudre cette problématique est d'utiliser une variable qui va tenir le cumul depuis la première ligne. A chaque ligne, on ajoute la valeur en cours. Pour garder une variable, on doit passer par le code .NET.
Pour ce faire on passe par la fenêtre de propriétés du rapport, dans l'onglet Code.
Oubliez le confort de l'Intellisense, vous n'êtes pas dans Visual Studio, l'éditeur ressemble plutôt à Notepad. En espérant que Reporting Services 2008 apporte des améliorations dans ce sens (comme pour Integration Services). En plus, vous êtes limité uniquement à VB.NET comme langage.
Quant au code en lui-même il est assez simple. On garde un variable Shared (static) et on fournit une petite fonction pour mettre à jour et retourner le cumul. Ici j'ai choisi le type Decimal car je souhaite retourner une somme d'argent. Rien de plus simple :
Shared cumul As Decimal = 0.0
Public Shared Function GetCumulativeSum(ByVal currentValue As Decimal) As
Decimal
cumul += currentValue
Return cumul
End Function
Reste à utiliser ce code dans le rapport. Pour cela, on utilise une Expression dans un élément de notre DataRegion :
=Code!GetCumulativeSum(Fields!SalesAmount.Value)
Un des problèmes est que l'on ne peut pas utiliser cette technique de cumul à différents endroits. En effet, on ne repart jamais à zéro. Plutôt que de tenter de réinitialiser le cumul dans la première ligne d'une DataRegion, on préfèrera l'utilisation d'un dictionnaire dans le Custom Code. Voici le code utilisant un dictionnaire :
Shared cumuls As
System.Collections.Generic.Dictionary(Of String, Decimal) = _
New System.Collections.Generic.Dictionary(Of String,
Decimal)
Public Shared Function GetCumulativeSum(ByVal currentValue As Decimal, ByVal
sumKey As String) As Decimal
If Not cumuls.ContainsKey(sumKey) Then
cumuls.Add(sumKey, 0.0)
End If
cumuls.Item(sumKey) += currentValue
Return cumuls.Item(sumKey)
End Function
Dans le rapport, on utilisera l'expression suivante :
=Code!GetCumulativeSum(Fields!SalesAmount.Value, "salesInChart")
...
=Code!GetCumulativeSum(Fields!TaxAmount.Value, "taxInMatrix")
Note : pour faire du C#, il faudra coder la fonction dans une assembly et la référencer dans le rapport.







Commentaires
Bonjour,
Saurais tu à tout hasard comment sommer une durée.
Car le SUM ne marche pas sur un DATETIME.
Merci
Il faut que ta requête contienne déjà une durée et non une date (ou en sus), ainsi tu auras accès aux agrégats par défaut. Sinon, ce doit être possible de le calculer via le moteur d'expressions ou, au pire, via du code intégré mais je n'ai pas la solution en magasin. A l'occasion, je la publierai. >?xml:namespace prefix =" ""o" ns =" ""urn:schemas-microsoft-com:office:office" /?<
Bonjour,
Ton article m'a bien aidé, car il m'a permis de savoir qu'il était possible d'utiliser du code custom .NET dans les rapports Reporting Services. J'ai donc opté pour cette solution.
Comme SUM ne marche que pour les integer ou les float, j'ai fait une première fonction GetTicks qui convertit la date en entier. Puis j'applique sur la somme, une deuxième fonction GetFormatedTimeSpan qui convertit l'entier en durée, et l'affiche sous forme de string.
Voici le code VB :
Public Function GetTicks(ByVal dt As DateTime) As Long
Return dt.Ticks
End Function
Public Function GetFormatedTimeSpan(ByVal ticks As Long) As String
Dim ts As New TimeSpan(ticks)
Return ts.ToString
End Function
Et la formule que j'ai utilisée :
=Code.GetFormatedTimeSpan(Sum(Code.GetTicks(Fields!SumAgtShiftDuration.Value),"AgentGroup3"))
Merci d'avoir pris le temps de me répondre !