Get an Average and a Sum in a Reporting Services Subtotal

You would think that if you wanted something simple like having a subtotal line with a sum and an average that this would be easily configurable in Reporting Services. Alas… Clicking on the Subtotal button magically adds a row to the matrix component. But, you cannot tell it what function to use: it will always show the sum of the numbers above. There is also just one row that can be added.

ReportingServicesSubtotal

Frustrating, if you want to achieve something simple like this:

SumAndAvg

You will need to apply a few tricks to achieve the above result.

First of all, it is possible to put multiple values inside a single cell. If values are put in a string and seperated with linefeeds they will appear as if on seperate rows.

To demonstrate, replacing the text “Total” in the subtotal row with the expression ="Sum" + vbcrlf + "Avg" will show two row headers (albeit in a single row, but that is good enough for me).

The next trick is to call custom code to calculate the cell values. The custom code, a function, returns a string containing either a single value (when inside the matrix) or two values in two “rows” (when in the subtotal row).

Have a look at the code:

    Public Function MatrixCellValue(ByVal sumValue As Object, ByVal avgValue As Object, ByVal InScope As Boolean, ByVal sumFormat As String, ByVal avgFormat As String) As Object
        If InScope Then
            Return sumValue
        Else
            If Not avgValue Is Nothing Then
                Return String.Format(sumFormat, CDbl(sumValue)) + vbCrLf + String.Format(avgFormat, CDbl(avgValue))
            Else
                Return Nothing
            End If
        End If
    End Function

Let’s go over each of the input parameters:

  • sumValue is the sum that is either shown inside the matrix area or in the subtotal row. This value will in any case be included in the return value of the function.
  • avgValue is the average value as calculated by Reporting Services. It should only be in included in the return value of the function when the function is called from the subtotal row.
  • InScope is a boolean that indicates whether the function is called from inside the matrix area or outside of it.
  • sumFormat and avgFormat are format strings that will be applied to the sum and average values.

Now replace the expression in the matrix cell with the function call below and you will get exactly the result as pictured above!

=Code.MatrixCellValue(
                     Sum(Fields!Count.Value),
                     Avg(Fields!Count.Value),
                     InScope("matrix1_Date") and InScope("matrix1_Product"),
                     "{0,6:N0}",
                     "{0,6:N1}")

In this example, the matrix groups are matrix1_Date for row grouping and matrix1_Product for column grouping. Hence InScope("matrix1_Date") and InScope("matrix1_Product") indicates whether or not the current cell is inside the matrix area or not.

ReportingServicesFunctionCall

A little word on the format strings: "{0,6:N1}" means: replace the 0 with a numeric having 1 decimal and pad the result with spaces so that the result is 6 characters long. For more info about format strings see the MSDN documentation.

12 Comments »

Comment by Barretto
2009-04-02 02:30:52

Good tip. After looking for it all over the internet I just found a good answer here in this article.
Congratulations !

 
Comment by Tom VdP
2009-04-08 11:11:32

Thank you :-) That is a bit the idea behind this blog: when I encounter a problem for which I cannot find a solution on the net, I post a solution here (if I find one and if time allows…)

 
Comment by Bruno Santos
2009-07-08 16:44:39

Tom, the solution is very good, more for me is repeats the values also on the fields above, no only on the total field. How I can correct?

Thanks

Bruno Santos

 
Comment by Tom VdP
2009-07-13 16:40:53

Bruno, double-check that what you have put in the expression in the matrix field value is correct. Especially the names of the groups inside the InScope functions.
Hth,
Tom

 
Comment by SANTOSH
2009-08-29 18:11:36

HI, your article is very good , this has solved my problem.

 
Comment by FHall
2009-09-18 19:58:43

This has been so helpful! I’ve got it to display what I want, the only issue is that I want the format to be different than “{0,6:N1}”. I need the number to be formatted based on a passed in setting (DecimalField). So, it might be 3 or it might 2 or 1 for formatting. I can’t hardcode 1. Any suggestions to being able to use the value of a passed in field? Thanks for any help!

 
Comment by FHall
2009-09-18 20:06:44

Ha! I just figured out the answer to my question. I was able to do this in the field:

“{0,6:N” & Fields!DecimalPositioner.Value & “}”

Pretty simple. I appreciate all the great advice above!

Thanks!

 
Comment by dragoshel
2009-09-22 12:44:16

I worked as a charm!
Great blog, thanks a lot!

 
Comment by Terese
2009-10-15 14:48:19

I am trying to implement the above approach, but am only getting the total once. e.g.

Jan Feb Mar Total
Sales Dollars 10.00 10.00 10.00 30.00
Sales Discounts -3.00 -3.00 -3.00 -9.00

A regular subtotal would yield 7.00 7.00 7.00 21.00

what I’m getting when I add the code is this:

Jan Feb Mar Total
Sales Dollars 10.00 10.00 10.00 30.00
Sales Discounts -3.00 -3.00 -3.00 -9.00

My New Total 21.00

I’ve double check my syntax.

 
Comment by Madhuri
2010-01-04 08:26:10

I have a query.
I am trying to get the average of a percentage column, and using the expression
‘ =Avg(Fields!SLA__.Value”) ‘ but its throwing error.
Any comments.

 
Comment by ReportingServices
2010-03-01 22:01:29

HI, your article is too good and this has solved my problem.
question:
Can I ues more than t values like Total & Avg and Max and Min?
When I try more then 2 its not working can you please advice.

Comment by Tom VdP
2010-03-08 14:16:07

Sure, since it is a string that is displayed in the cells, you could add as many values as needed. Just add them as arguments to the “MatrixCellValue” function and in that function concatenate the values seperated by vbCrLf’s.

 
 
Name (required)
E-mail (required - never shown publicly)
URI
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> in your comment.

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word

Trackback responses to this post