Showing posts with label Reporting Services. Show all posts
Showing posts with label Reporting Services. Show all posts

Tuesday, 11 September 2007

Reporting Services, Hierarchy's and cross Browser Problems

This week I have been doing some Report development for a custom application we have been developing at work. Given everything is SQL based we opted to build the reports using Reporting Services.

On the whole the reports are pretty straight forward. However there were 2 challenges.

The first is around hierarchical reporting. With in the application people can belong to different Occupational Units's(OU). One of the business rules for the reporting is 'A user can only report on their own OU and any OU that is below them.

To achieve this I ended up building a recursive function that returns a Scalar Table that works out all the OU's a specific user can see. I then use that in my where clause.

The Table Function looks like this

CREATE FUNCTION [Generate_OUTree] 
(
-- Add the parameters for the function here
@OUID [uniqueidentifier]
)
RETURNS @OUTree TABLE
(
OUID [uniqueidentifier],
ParentID [uniqueidentifier],
OUName Varchar(500),
Level Int
)
AS
begin

-- Add the SELECT statement with parameter references here
With OUTree (OUID, ParentID, OUName, Level)
As
(
-- Anchor Member defination to get top level OU
Select OUID, ParentOUID, OUName, 0 as Level
From CustomerOUView
Where OUID = @OUID
UNION ALL
--Recursive member defination to get child companies
Select CCV.OUID, CCV.ParentOUID, CCV.OUName, Level + 1
From CustomerOUView CCV
Inner Join OUTree
On CCV.ParentOUID = OUTree.OUID
)

insert into @OUTree
Select * From OUTree
RETURN

As you can see I pass in a parameter that is the ID of the users OU.






 






To actually use this to achive what I want I am calling he function like this






 







    Select *
From dbo.staffView
Where OUID IN(Select OUID From dbo.Generate_OUTree(@OUID))







This effectively returns all the rows from my view where the OUID in the view is in the list generated by my function.






 






The follow on to this was we had to build a full OU tree report. The report shows each OU under its parent and indents teh list so it is wasy to see which child OU belongs to Which parent.






 






The hard part was to be able to sort the report so that the OU structure was returned in a format that made it easy to group the OU's together.






 


CREATE PROCEDURE [Report_GenerateOUList]
-- Add the parameters for the stored procedure here
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for procedure here
With OUTree (OUID, ParentID, OUName, Level, Sort)
As
(
-- Anchor Member defination to get top level OU
Select OUID, ParentOUID, OUName, 0 as Level ,Cast(OUName as Varchar(4000))
,OperatorCategoryName,MembershipCategoryName
From CustomerOUView
Where ParentOUID = '00000000-0000-0000-0000-000000000000' --top level OU has no parent


        UNION ALL
--Recursive member defination to get child OU's Select CCV.OUID, CCV.ParentOUID, CCV.OUName,
Level + 1, Cast(Sort + '|' + CCV.OUName as Varchar(4000))


        From CustomerOUView CCV
Inner Join OUTree
On CCV.ParentOUID = OUTree.OUID
)
Select * From OUTree
Order by Sort





In the database the OU ID's are all GUID's and as I wanted all OU's displayed in this report I have hard-coded for the top level OU.






Inside Reporting Services I am using the following to get indentation






=(Space(Fields!Level * 5) + Fields!OUName.Value)






This then causes 5 spaces for each level down the tree to be inserted in front of the OU's Name.






 






Once I had all this going and deployed to my Report Server everything appeared to be working fine when I viewed the reports with IE7. The only remaining thing to do was do a second check on the reports using Firefox.






Firefox and Reporting Services have a few issues. Due to he way RS renders the reports in IFRAME's Firefox causes them to get squashed up and not display correctly. After some frantic searching, Google is your friend smile_wink, and a bit of testing on a couple of report servers  found the following.






First-up Firefox only shows the top 2 to 3 cm's of your report. The rendering puts it a small IFRAME instead of expanding out down your 'page' the way IE does. This is fairly easy to resolve, thanks to Jon Galloway's blog for this answer. You need to edit the ReportingServices.css. On my machine it lives here "C:\Program Files\Microsoft SQL Server\MSSQL.3\Reporting Services\ReportManager\Styles\"






In the css file you need to add the following entry.



/* Fix report IFRAME height for Firefox */
.DocMapAndReportFrame
{
min-height: 860px;
}





 






This forces Firefox to use a taller IFRAME.






 






I also found that the width of the report was getting squashed up on my deployment server, although on my laptop's report server it wasn't happening. On investigating the two machines the only thing I could find was a difference in the build versions of the 2 SQL servers. The Deployment server is using SQL2005 SP1 while my laptop is SQL2005 SP2.






 






As a work around I found that by putting an empty text box in the header of my reports that was the full width of the report Firefox no longer squashes up the report. While ideally I will update the server with the latest SP for SQL this is acting as a work around for the time being.






 






Monday, 25 June 2007

Reporting Services on Dynamics NAV

 
When using Reporting Services with Dynamics NAV there are a number of things to take into consideration.
 
One of the main things to consider is the way the SQL Tables are structured with Dynamics NAV. For each company in the database there will be a set of company specific tables. These are prefixed Company Name$. So for example the Customer table for a company called CRONUS International Ltd. is CRONUS International Ltd_$Customer.  Note the '.' at the end of the company name has been replaced with an '_'
This is based off of a setting in NAV that defines which special characters are replaced, and is done to make life simpler in SQL.
 
This means that when writing reports you need to know the company name of the NAV Company you want to report on. Where there is only 1 Company in the database this isn't to painful, however as a developer it means every time you want re-use a report into a different company you need to go back in and change the Company name part of each table. It also means that, assuming you are going to deploy your reports to a test environment prior to a live deployment' that your NAV Company in the test system has to be the same as in your live one, a practice that can cause other confusions when using the NAV Client.
 
To get round this problem you can do one of 2 things.
  1. You can generate a SQL View to present the data you want to report on and leave the company name out. This at least makes the reports cross company compatible as you only have to build the views once for each company.
  2. If you are basing your Reports on data prepared by stored procedures you also have the option of using dynamic SQL and passing the Company Name as a Parameter at run time.
Both of these options also are fine where you have multiple companies in the database as you can add an identifier to the SQL View and use a Parameter in the report to filter for the correct data.
However, as with a project I am currently working on, when you have multiple companies and the prospect of more being added and some being closed out on a regular basis the prospect of keeping the SQL Views up to date can force you to use the second option only, i.e. use dynamic SQL and pass the company name as a parameter.
 
Another thing to consider is that not every field you can see in the NAV client is actually held on the underlying SQL Tables. NAV flowfields are one such example. Form experience this can make what appears to be a simple report very complicated.

Reporting Services Overview

Reporting Services is a part of Microsoft SQL Services. It first appeared as an optional download for SQL2000 and is a standard option for SQL2005.

As its name implies it is a reporting tool. More specifically its a web based reporting tool built on SQL but that allows reporting on any data source that you can create an ODBC connection too.

Predominantly I use SQL databases as the data source, although I have also built reports using Analysis services as the data source.

The principle is very straight forward. Using Visual Studio 2005 you create a new report. Link it to a data source, either defined specifically in the report or by using an external shares link.

You can then write SQL queries against the data in a series of data sets. You can also set a data set to execute stored procedures on the SQL database. This allows for very complex queries to be written.

Within the report you have access to a number of different controls, including graphing and pivot table style controls.

You can specify that some controls are dependant on other controls and only appear when the parent is selected.

Another useful tool is the principle of 'drill through' reports. These are effectively extra reports that are called when part of a report is selected. All appropriate parameters are passed down to the new report. This allows you to write summary reports with the drill through allowing you to have details when needed.

Another feature of Reporting services is the ability to subscribe to reports. This allows a user to pick a report from the report server and specify when they would like to automatically get it. They can also specify the format the report should be delivered in, e.g. pdf, Excel Spreadsheet, tiff etc. The can set what parameters the report should use and where it should be delivered to. This allows a sales manager, for example, to have the previous days sales results delivered at 8am to his email as an excel spreadsheet.


One final tool that comes with some of the versions of Reporting Services is Report Builder. This is a web deployed report designer. It requires that a data model has been built in advance but once that has been done then an end user can use the Report Builder to build ad hoc reports on the data source. These could be one off reports or if the user decides that the report will be useful to other users they can deploy the report back to the report server where it becomes available to all users.

The Report Library itself is either accessed via its own web site or it can be linked to Microsoft SharePoint. Where it is linked the reports appear in their own library inside the SharePoint portal and can be used in the same was as from the web site.