March 2013

You are currently browsing the monthly archive for March 2013.

Fruit Basket (ref. http://ciaopaolo.com/store/category/fruit-gift-baskets/)If you’re reading this, you’re probably already aware that SQL Server Reporting Services has got some useful collections that can be used in expressions all over the report?  Well, just in case you’re not, I’ll cover not just the hidden ones but all of them.

Collections, huh?

If you’ve got some programming experience then I’m sure this concept is familiar to you.  On the other hand, and in that case you’re new to all this, think of a collection as a, well… a gathering of objects.  Similar to a fruit basket which is a collection of fruit.

Let’s first have a look at the syntax, how can these collections be used?

I’m using SSRS 2012 SP1 but this concept is not new.  I believe all expression will even work in SSRS 2005.

Collection Syntax

Each item in a collection can be referenced through two different methods, both giving the same result.  Let’s continue the fruit basket example.  If SSRS had a collection called FruitCollection, you’d be able to reference the different fruits in that basket through following syntax:

FruitCollection!FruitName

For instance FruitCollection!Lemon will give you the Lemon object, assuming such an object exists in the collection.  That’s the first method.  The advantage of this method is that the expression builder will display a nice popup list of all the items in the collection once you’ve typed the exclamation mark.

The second method of referencing an item in the collection is by using the following Visual Basic syntax:

FruitCollection("Lemon")

This syntax requires you to pass the object name as a string.  As a result of that, you don’t get any syntax checks on the object name, so if you’d typed Limon you would only notice the problem when you actually run the report and get an error.  That’s why I prefer using the syntax with the exclamation mark so that’s the syntax I will be using for the examples further down in this article.

Each object in a collection also has a number of properties that can be consulted.  To continue the fruit basket example, the Lemon object could have a Color property.  To access that property you would use this expression:

FruitCollection!Lemon.Color

Alright, time to have a closer look at the different collections in SSRS!

The Parameters Collection

If you’ve got any experience implementing report parameters, I’m sure you already know this one.  The Parameters collection allows you to access your report parameters.

In case you’re dealing with a multiple-valued parameter, there are a couple of interesting properties you should be aware of, such as the Count and IsMultiValue property.  Careful though: the Count property returns the number of selected values, not the number of available values!

To reference just one of the selected values you can use the following syntax:

Parameters!YourParameter.Value(0)

This expression will return the Value property of the first item in the selected items list.  Note that it’s a zero-based index.

Another interesting function you should be aware of is the Join.  It allows you to join the different selected values together into one string.

The screenshot below shows you some expressions and their result.  The Category parameter has got three available values with two of them selected.

The Parameters Collection

The Variables Collection

The Variables collection gives you access to the report variables.  To demonstrate this, I’ve set up the following variable:

Report Variables

And here’s the expression to access its value:

Variables!MyVariable.Value

The Globals and User Collections

The Globals and User collections contain some useful properties and are provided by default in every report.  These are the items available through the Built-in Fields category in the expression builder:

The Built-in Fields: objects in Globals and User collection

Through those collections you’ve got access to some really interesting properties, such as the RenderFormat.Name property which indicates what output format is being rendered.  I’ve actually mentioned this one before: Hide/Show Items Dependant On Export Format (SSRS)

Okay, time to get started with those hidden collections.  But first, why do I call them hidden?  Simple, because they are not shown in the expression builder Category list, as you can see from the previous screenshot.

The (Hidden) ReportItems Collection

A very commonly used collection is the one called ReportItems.  It allows you to reference the different textboxes on your report.  If you know that each “cell” in a Tablix is actually a Textbox, well, I’m sure you realize that this can be quite useful in certain situations.

Let’s have a look at a basic example.  Say I want to retrieve the list of selected Category values that’s shown in the screenshot in the Parameters Collection subchapter above.

Tip: always give your textbox a clear name when you’re going to reference it in an expression.  Never use the default Textbox666 name.  You can rename a textbox by changing its Name property.

In the following expression you can see that I’ve given the textbox another name, one that indicates what it contains:

ReportItems!txtFilterValues.Value

And here’s the result of that expression:

Using the ReportItems collection

Tip: the above is only possible if the textboxes are not in a group in the tablix.  So the tablix on the left does not contain any grouping, it’s a simple table with five basic rows and two columns.

The (Hidden) DataSources and DataSets Collections

Finally we’ve come to the collections which made me write this article.  Did you know it’s possible to display your dataset query in your report?  That’s right, through the DataSets collection you can access your actual query string!  And through the DataSources collection you have access to some other properties, such as the source type and the shared data source being referenced.

My report has got the following data sources and datasets defined:

Data Sources and Datasets

As indicated by the arrow in the data source icon, AdventureWorksDW2012 is referencing a shared data source while tempdb_embedded is an embedded source in the report.

Here are some examples of possible expressions and their result:

Using the DataSources and DataSets collections

Through the DataSources collection you have access to a Type property on the source.  This property is only given a value in case of an embedded data source.

You also have access to a property called DataSourceReference.  It contains the name of the shared data source being referenced so only contains a value in case of a shared data source.

And through the DataSets collection you can access the CommandText property, which returns your actual query statement.  This can be particularly useful when you’re building your query dynamically through an expression, very interesting for troubleshooting!

There’s also a property called RewrittenCommandText.  When I initially saw that property I thought it would return the statement with any parameters replaced with their actual values.  Well, I was wrong, as the screenshot above indicates.  Apparently this property is used for model-based queries, as mentioned by Robert Bruckner.  I try to avoid report models…

Conclusion

This article introduced the concept of collections in Reporting Services and then went into explaining the use of each of them, including a couple of hidden collections.

Have fun!

Valentino.

References

Built-in Collections in Expressions (Report Builder and SSRS)

What DataSet Query Text Is Executed?

Share

Tags: , ,

Ever since I started using @ValentinoV on Twitter a bit more actively, which is now more than a year ago, I have also been exploring different methods of announcing my new blog posts to the world.  One of the methods I use is sending out a couple of tweets to my followers.  So far I had been adding the prefix [Blog] as a standardized way of working and I also add relevant hashtags, such as #SSRS when the post is about Reporting Services.

Here’s an example:

Tweet using the [Blog] prefix

Then Jamie Thomson, aka SSIS Junkie, made me aware of a blog post he had posted earlier this week.

The power of Twitter: being able to quickly contact someone without the need of email

And in that post, he introduced an interesting alternative to what I (and a lot of other SQL Server bloggers) was doing!  Instead of using that [Blog] prefix it’s better to use a hashtag!  Why is that better?  Well, because searches and filters on hashtags work better than searches on just plain text. In fact, he proposes several hashtags.  Have a look at his post for the details: Bootstrapping SQL Server bloggers and blog readers with Twitter!

And here’s my earlier tweet reworked as per Jamie’s proposed standards:

Tweet using Jamie Thomson standards

However, the #blogged hashtag is not the one I will be using.  Several other bloggers commented on his post that they’re more in favor of the concatenation of #blogged and #sqlserver into #sqlblog.  I like that proposal because it’s closer to my earlier prefix and it uses less characters.  Given the nature of Twitter, if we can deliver the same message using less characters then that would be the preferred method, right? So that’s the one I will be using from now on!

I’ll even demonstrate it by updating this post once I’ve tweeted about it.  Yeah, a recursive blog post!

Tweet to demonstrate usage of the adapted standard

Have fun, and spread the word!

Valentino.

Share

Tags: ,

Unfiltered Coffee - http://www.flickr.com/photos/derektor/92480692/In this article I’ll be describing a method which you can use to filter data in your Reporting Services reports without making any changes to the dataset query.

To get started, I’ll first imagine I’m being interviewed.  (Yeah, I like that.)

Q: You mentioned “without making any changes to the dataset query”.  So you’ll be filtering on the SSRS side then?

A: (Darn, I think she’s onto me.)  Well, yes.

Q: Would you recommend this method?

A: (Yep, she is.) Well, erm, no.  For performance reasons it’s much better to filter on the database server side.  You don’t waste any network bandwidth and database servers are specialized in filtering data.

Q: Then why are you writing an article about filtering on the report side?

A: Well, because sometimes you don’t have another option.  Not all data sources are as flexible as SQL Server, and SSRS supports many different providers.  In some occasions, the DBA that supports exotic data source X gives you a command, similar to a stored procedure call, that returns the data for your report.  And you don’t get any say on how that gets implemented, you’re just told to use that command.  Unfortunately that command returns items A-Z while the report has an item filter.  In those scenarios, it’s interesting if you’d be able to filter on the report side.

Q: Let’s say I would like to filter on the database server side, how would I do that?

A: Just use the WHERE clause in your query.

Alright, enough intro, time to start the article!

To build the report I’ll be using SQL Server 2012, more precisely:

Microsoft SQL Server 2012 (SP1) – 11.0.3000.0 (X64)
Oct 19 2012 13:38:57
Copyright (c) Microsoft Corporation
Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1)

I’ve made the RDL available for download from my SkyDrive.

The Scenario

You’ve been asked to develop a report that shows a list of products, grouped by category.  The report needs to take a filter on product category into account.  The values on which you need to filter are stored in a configuration table.  You’ve been given a query which for some mystical reason can’t be modified.

Weird enough?  Okay, let’s get that implemented then!

The Report

Let’s first set up a simple report with a dataset and a table.  The table groups the products on category:

A Grouped Table

In Preview it would look like this:

List of products grouped on category

The dataset used in the report above is called ProductList and uses the following query:

select DPC.EnglishProductCategoryName ProductCategoryName
    , DPS.EnglishProductSubcategoryName ProductSubcategoryName
    , DP.EnglishProductName ProductName
from dbo.DimProduct DP
inner join dbo.DimProductSubcategory DPS
    on DPS.ProductSubcategoryKey = DP.ProductSubcategoryKey
inner join dbo.DimProductCategory DPC
    on DPC.ProductCategoryKey = DPS.ProductCategoryKey
order by DPC.EnglishProductCategoryName, DPS.EnglishProductSubcategoryName
    , DP.EnglishProductName;

Retrieving The Filter Configuration

So now we need to filter this report based on configuration stored in a table.  That means we’ll need an additional dataset, let’s use the following query and call it CategoryFilter:

select 'Category' FilterName, 'Components' FilterValue
union all select 'Category', 'Clothing'

(Sure, I’ve hardcoded the configuration data but for scenario’s sake, imagine it’s coming from a table.)

Here’s what the result looks like:

The Category Filter

The dataset contains two fields: the name of the filter and a value on which to filter.  Each value on which we need to filter has its own record.  Having this FilterName field in the table means that it can be re-used for several different filters, if needed.  Your dataset would then use a WHERE FilterName = ‘YourFilter’ clause.

Now, one crucial question remains: how can we use this dataset to filter the data from the other dataset?

Depending on your requirements, there are several possibilities. If you’re sure none of your data regions require the data that will get filtered out, you can use the Filter options on the Dataset.  Alternatively you can use the Filter options on your data region.  In any case, those filters all use the same interface, so implementation-wise it’s all the same.

I’ll implement the filter on the tablix, this gives me the opportunity to show how to get to the properties (dataset is easier).

Okay, so how do we implement a filter on a tablix?

First select the Tablix and right-click the grey square in the top left corner:

Opening the Tablix Properties

Select Tablix Properties and switch to the Filters page.  Click the Add button to add a filter.  As you can see, filters support expressions.  That’s a good thing!

In the Expression combobox, select the field on which you want to filter the data.

The Operator that fits with our requirements should be one that supports multiple values.  In case you’re wondering why, take a good look at our CategoryFilter dataset mentioned earlier.  We want to filter on both Components and Clothing.  So the default equals sign is not really what we’re after, the IN operator will serve much better.

The only remaining empty textbox is Value.  How can we get the values from our filter dataset into this textbox?  In any case, we’ll need to use an expression so click the little fx button next to the Value textbox.

Adding a Filter to the Tablix

As you’re probably aware, a data region can only be linked to one dataset.  Which means we can’t say:

=Fields!FilterValue.Value

because FilterValue doesn’t exist in the dataset that’s linked to the tablix.

So how can we implement a filter based on data from another dataset?  Once again we’ve got several options.  Let’s look into them!

Option One: Report Parameter

If we’d set up a Report Parameter, we could reference that, right?  Let’s close the properties popup for now (click OK) and create a new report parameter:

Adding a report parameter

Our parameter is called CategoryFilter, its type is Text and it should allow multiple values.  We’ll also set visibility to Internal because it doesn’t need to get exposed in any way.

The parameter’s default values are the values retrieved by the CategoryFilter dataset, so switch to the Default Values page and specify the dataset as shown in the screenshot:

Retrieving the default values from a query

With the parameter created, switch back to the Filters page on the Tablix Properties and enter the following expression:

=Parameters!CategoryFilter.Value

If you’ve created the expression by double-clicking the parameter in the Values box, don’t forget to remove the (0) or your data will get filtered on the first item only.

Click OK and render the report:

Report Preview now shows Clothing as first category

It’s working!  Accessories is no longer the first category that gets shown because it’s been filtered out.  The data is now filtered on the configuration as specified through the second dataset.

But… do we really need to set up a report parameter for this?  Well, no!  Let’s investigate option number two.

Option Two: The LookupSet Function

A couple of years ago I wrote an article to explain how you can retrieve data from another dataset through the new lookup functions.  Well, “new” at the time meant SQL Server 2008 R2.  We’re now on 2012 so the functions still exist!

The function that can help us out today is LookupSet.  Open up the Filter properties once again and replace the Value expression with the following:

=LookupSet("Category", Fields!FilterName.Value, Fields!FilterValue.Value, "CategoryFilter")

Close the popup window and preview the report.  If it runs fine, delete the report parameter and run the preview again.

Filtering the data using the LookupSet function

Yes, it still works, nice!  So we don’t need to use a report parameter to filter our data, we can use a fairly simple expression using the LookupSet function!

Option Three: The Split Function

To finalize let’s investigate a variation on the requirement.  In this variation, the filter configuration doesn’t need to come from a table.  It can just be hardcoded in the report.  Can we do that, without using an additional dataset?  Yes we can!

In the Filter properties, change the Value expression to:

="Components,Clothing"

Now render the report:

Oh no, the data is gone!

Hmm, that didn’t work well.  Ow right, the IN operator expects an array of string values and not a comma-separated value string.  Let’s see, how can we get an array out of a character-separated value string?  Actually, I’ve covered this in one of my #tsql2sday posts.  We can use the Split function:

=Split("Components,Clothing", ",")

With that expression specified, let’s render the report a last time:

Filtering the tablix using the Split function

Woohoo, it works once again!

Conclusion

In this article I’ve demonstrated three different possibilities to implement filtering on multiple values on the report side.  It is not a recommended method but in some cases it can be very useful, especially when you don’t have another choice!

Have fun!

Valentino.

Share

Tags: , , , ,

© 2008-2017 BI: Beer Intelligence? All Rights Reserved