14 Aug 2008

Complex Reporting: Part 5 - Wrap up

Over the last four parts (1, 2, 3 and 4) you’ve seen how to build this complex SRS report, but there are a few points to be aware when building reports like this, first this is not a really scalable solution, both in computation cost and development cost. Sub-Reports add a lot of over head to the CPU and RAM and the fact that for each year you want to include you have to add more SQL. Thankfully in this example we had 3 years and 3 commodities. In the real world, which inspired me, it was also only three years with a low number of items (sub 25) so the performance considerations were ok.
The next problem is the Export To option in SRS, where you can export to a variety of formats such as PDF, Excel etc… Having sub-reports within table cells is NOT supported by the Excel one, you just a gray block were the sub report would be. PDF, TIFF, and web archive all work fine. If your users are expect to export to Excel you need to rethink using this.
Lastly you have to make sure you set the width and height and lock the cells on the report and sub-reports to not expand and shrink. If you don’t get the width/height the same all over what happens is your cells don’t align between the report and sub-reports and it looks shocking.
11 Aug 2008

Complex Reporting: Part 4 - Introducing Sub-Reports

A sub report is a report which is embedded into another report, basically it’s SRS answer to IFRAMEs. This should not be confused with the ability to drill through from one report to another, as those render separately and are provided separately. With sub-reports the main report renders, then the sub-report then the output of all of those is combined to produce a single report. Sub-reports are normal SRS reports as well, so they have the same features as other reports.
So how do we use them? Well if we look back at our previous image where we had the fields scattered all over there is a distinct pattern here, basically there are 5 blocks (Q1, Q2, Q3, Q4 and Total) in a row under each fiscal year for each commodity/deal, and the horizontal total row at the end is basically the same.

What we can do is merge those five cells on the table together and insert a sub report into that merged cell, and since all the groups are the same they can all point to the same report. The exception is the horizontal total row, which is the same in look is calculated a little differently. So we only need two sub-reports and we would structure it as follows:

So how does the sub report know what to show? Well remember it’s a normal SRS so you can just parameters to it, and because it’s in a cell of a table you can just access the values from row that is being rendered. So all we need to do is pass two parameters, the fiscal year and the commodity.
Now the complexity is easy since it’s just a simple bit of SQL using the same UNION stuff as we used before:
SELECT     f1q1value, f1q2value, f1q3value, f1q4value
FROM         Deals
WHERE     (deal = @projectid) AND (fiscal1 = @fiscal)
SELECT     f2q1value, f2q2value, f2q3value, f2q4value
FROM         Deals
WHERE     (deal = @projectid) AND (fiscal2 = @fiscal)
SELECT     f3q1value, f3q2value, f3q3value, f3q4value
FROM         Deals
WHERE     (deal = @projectid) AND (fiscal3 = @fiscal)
SELECT '0','0','0','0'

If you read that and saw the last SELECT and went, WHOA, good for spotting it. What’s happening is that I always want a result regardless, so that I don’t get issues caused by missing fields. So by adding that and only selecting the top record I ensure that there is always a value, even if it is zero. The total column on the sub report is just a calculated field adding the four values up.
For the total row sub report, it’s basically the exact same except we are now wrapping the fields in SUM’s, that’s the only change. The last thing to make sure of is that for the initial table on the main report you get all the commodities for all the periods. To do that your SQL needs to take into all the possibilities like so:
SELECT     Deal
FROM        Deals
WHERE     ((fiscal1 = @FiscalYear) OR (fiscal2 = @FiscalYear) OR (fiscal3 = @FiscalYear) OR (CAST(RIGHT(fiscal2,2) AS Int) = CAST(RIGHT(@FiscalYear,2) AS Int)+1) OR
(CAST(RIGHT(fiscal2,2) AS Int) = CAST(RIGHT(@FiscalYear,2) AS Int)+2) OR (CAST(RIGHT(fiscal3,2) AS Int) = CAST(RIGHT(@FiscalYear,2) AS Int)+1) OR (CAST(RIGHT(fiscal3,2) AS Int) = CAST(RIGHT(@FiscalYear,2) AS Int)+2))
@FiscalYear is the name of our drop down we mentioned earlier and we use a little bit of SQL to get it into an INT and manipulate it to give us every possible combination.
02 Aug 2008

Complex Reporting: Part 3 - Structure

So in part two I showed what was needed, so now how do we actually build this report. Well if your gut said to use a table or matrix then you would quickly hit a problem because what data needs to be shown in each field is not constant. A picture may help explain what I mean. If we look at our previous example:




Our fields would have to look like this:



So note how F1Q1Value appears in a different place in each row, try building that in a table or  matrix. You just can’t! Also now think about the requirement for sub totals, going horizontal is ok in concept but going vertical is tough because you are adding the values of a lot of different fields together.

So how do you go about building this? Well the financial year indicators at the top could just be calculated from the value from the drop down and put into three text boxes. The next row, which is the header row for quarters could also be text boxes or the header row of a table since it doesn’t change, then we would need a table below that for the commodity names and values, but how do we get the values of the field to dynamically change based on the commodity? If you go back to part 1, you’ll remember I mentioned sub-reports, but I will get to that next time.

28 Jul 2008

Complex Reporting: Part 2 - Report Requirements

In part 1 we looked at the requirements at a high level and also looked at the data structure, in part 2 we will now look at the finer details of the requirement. First the user needs to be able select from a drop down, which contains a list of all possible fiscal years, the first fiscal year they want to see, next the report must show blank spaces for commodities which do not feature in that fiscal, but may feature in future fiscals and lastly we need sub totals for years and commodities.
So the drop down is a simple SRS parameter which is connected to a data set which does a simple SQL command:
and then set the value and name of the drop down to the Fiscal field.
The next requirement is actually telling us something very subtle, which is at the core of the complexity. That is that if I choose FY06, the report will render FY06, FY07 and FY08 and that if a commodity starts in any of those years it must be shown. So we are not ONLY showing what starts in FY06, we are showing things that start in FY07 and FY08 too. This means our final result should look like:

If you are a regular SRS developer your gut is telling you that it is just a table, or maybe a matrix, unfortunately it’s a little more than that. But we will look at that next time.
The last requirement, sub totals, is very easy and logical (especially looking at the image above) so I am not going to go into detail about that.
24 Jul 2008

Complex Reporting: Part 1 - Introduction

Recently I got the chance to build a report using Microsoft SQL Server Reporting Service 2005 for a customer, that in itself is nothing fantastic. However this was one of the most complex reports I have ever had to build, for two main reasons:
  1. What needs to be displayed is so simple in concept, that you get misled into thinking it’s easy.
  2. To do this you need to use a component of SRS which is seldom needed, sub-reports.
But before I give away too much let me explain what the report should show, the customer I am using in this series, tracks the deals for commodities over a three year period, broken down to each quarter. So they want to know in year 1, quarter 1 they sold x values worth of beer, and so on for all 12 quarters. As they are constantly adding new commodities the year 1 is not the same for each commodity. So they may start selling beer in 2008 and chickens in 2009, so they would only sell beer until 2011 but chickens would be sold until 2012. And all we need is a report to show this.
Disclaimer: Most of this has been changed to protect the innocent, so the report images are drawn in Visio and are not real images, the customer doesn’t sell commodities (especially not coffee and beer) and the data is completely faked.

So lets look at the data structure, it’s a simple single table (no I didn’t have anything with the design of this), which has a Deal field for the name of commodity; Fiscal1, Fiscal2, Fiscal3 store the years that relate to each year we are tracking and the FxQxValue is the value for that year and quarter.

Lets look at how this would look with sample data, this is the same data we will use for the rest of the series:

Next time we will look at the report requirements itself and start to look at how to build it.
02 Nov 2007

SQL Server Express with Advanced Services

This really is the worlds most needed, most hidden and most marketing bs item ever. For those who don't know SQL Server Express is the light version of SQL Server, basically runs a database server but nothing else, not even a management tool. However it is free to redist with apps and it ships with Visual Studio etc... so it's out there a lot.
But you can just feel there are things needed to get it from almost useless to void filling tool (management tools being number 1). Anyway someone at MS realized this at some point in the last year and decided to bring out the Advanced Services edition (how is that for marketing spin, it should be the complete edition but no we need it to be advance, even though it install stripped down features of everything still).
Anyway above the standard express you get:
  1. Stripped down management tool
  2. Reporting services server (the /ReportServer, you don't get /Reports)
  3. and full text search.
These features are so advanced it's insane, oh wait they are all in the standard SQL server from day one.
Anyway if you need this you can get the 250 odd MB download, which you can just run on your vanilla SQL express to upgrade it, from
More details on this is available at