<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>A Developer&#039;s Blog &#187; Tutorial</title>
	<atom:link href="http://blog.hoegaerden.be/tag/tutorial/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.hoegaerden.be</link>
	<description>SQL Server, BI, .NET, IT and anything else I have been playing with.</description>
	<lastBuildDate>Sun, 11 Jul 2010 12:19:25 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Put Some Images On Those SSRS Reports</title>
		<link>http://blog.hoegaerden.be/2010/07/07/put-some-images-on-those-ssrs-reports/</link>
		<comments>http://blog.hoegaerden.be/2010/07/07/put-some-images-on-those-ssrs-reports/#comments</comments>
		<pubDate>Wed, 07 Jul 2010 16:05:21 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2010/07/07/put-some-images-on-those-ssrs-reports/</guid>
		<description><![CDATA[On the forums I now and then encounter questions regarding images on SSRS reports.&#160; Instead of re-inventing the wheel each time, I decided to write an article about the subject.&#160; So in this article I’ll be discussing and demonstrating several different ways of how images can be put on a report.
I’m using SQL Server Reporting [...]]]></description>
			<content:encoded><![CDATA[<p>On the forums I now and then encounter questions regarding images on SSRS reports.&#160; Instead of re-inventing the wheel each time, I decided to write an article about the subject.&#160; So in this article I’ll be discussing and demonstrating several different ways of how images can be put on a report.</p>
<p>I’m using SQL Server Reporting Services 2008 R2 CTP, more precisely version 10.50.1352.12, but the methods explained here will work on any SSRS 2008.&#160; Furthermore I’m using the AdventureWorks2008R2 database, <a title="AdventureWorks 2008R2 RTM" href="http://msftdbprodsamples.codeplex.com/releases/view/45907" target="_blank">available at CodePlex</a>.</p>
<p>The resulting report, including image files, <a title="SSRS and images download" href="http://cid-81c8b064cbbe1698.office.live.com/self.aspx/.Public/blog/SSRS%5E_and%5E_images.zip" target="_blank">can be downloaded from my Skydrive</a>.</p>
<h2>The Scenario</h2>
<p>The marketing department has requested a product catalogue.&#160; This catalogue should contain all products produced by our two daughter companies: The Canyon Peak and Great Falls Soft.&#160; The catalogue should be grouped on company, with the next company&#8217;s products starting on a new page.</p>
<p>Further requirements are:</p>
<ol>
<ol>
<li>Each page needs an image in its header, with even pages displaying a different image than odd pages. </li>
<li>Each company has a logo.&#160; The logo should be displayed in the company’s header. </li>
<li>Each product has a logo.&#160; The logo should be displayed as part of the product details. </li>
</ol>
</ol>
<p>A design document containing the expected layout, including all image material, has been provided.</p>
<h2>The Data</h2>
<p>The following query provides us with all the data needed to produce the report:</p>
<p> <a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a>
<pre class="code"><span style="color: blue">SELECT </span><span style="color: red">'The Canyon Peak' </span><span style="color: blue">as </span>Company<span style="color: gray">, </span><span style="color: red">'TheCanyonPeak_logo.png' </span>CompanyLogo<span style="color: gray">,
    </span><span style="color: red">'The Canyon Peak company specializes in all kinds of bikes, such as touring and road bikes.' </span>CompanyDescription<span style="color: gray">,
    </span>P<span style="color: gray">.</span>Name <span style="color: blue">as </span>Product<span style="color: gray">, </span>PS<span style="color: gray">.</span>Name <span style="color: blue">as </span>Subcategory<span style="color: gray">, </span>PC<span style="color: gray">.</span>Name <span style="color: blue">as </span>Category<span style="color: gray">,
    </span>PP<span style="color: gray">.</span>LargePhoto<span style="color: gray">, </span>P<span style="color: gray">.</span>ListPrice<span style="color: gray">, </span>P<span style="color: gray">.</span><span style="color: blue">Weight</span><span style="color: gray">, </span>P<span style="color: gray">.</span>Size<span style="color: gray">,
    </span>P<span style="color: gray">.</span>SizeUnitMeasureCode<span style="color: gray">, </span>P<span style="color: gray">.</span>WeightUnitMeasureCode
<span style="color: blue">FROM </span>Production<span style="color: gray">.</span>Product <span style="color: blue">AS </span>P
    <span style="color: gray">INNER JOIN </span>Production<span style="color: gray">.</span>ProductSubcategory <span style="color: blue">AS </span>PS
        <span style="color: blue">ON </span>PS<span style="color: gray">.</span>ProductSubcategoryID <span style="color: gray">= </span>P<span style="color: gray">.</span>ProductSubcategoryID
    <span style="color: gray">INNER JOIN </span>Production<span style="color: gray">.</span>ProductCategory <span style="color: blue">AS </span>PC
        <span style="color: blue">ON </span>PC<span style="color: gray">.</span>ProductCategoryID <span style="color: gray">= </span>PS<span style="color: gray">.</span>ProductCategoryID
    <span style="color: gray">LEFT OUTER JOIN </span>Production<span style="color: gray">.</span>ProductProductPhoto PPP
        <span style="color: blue">ON </span>PPP<span style="color: gray">.</span>ProductID <span style="color: gray">= </span>P<span style="color: gray">.</span>ProductID
    <span style="color: gray">LEFT OUTER JOIN </span>Production<span style="color: gray">.</span>ProductPhoto PP
        <span style="color: blue">ON </span>PPP<span style="color: gray">.</span>ProductPhotoID <span style="color: gray">= </span>PP<span style="color: gray">.</span>ProductPhotoID
<span style="color: blue">WHERE </span>PC<span style="color: gray">.</span>Name <span style="color: gray">= </span><span style="color: red">'Bikes' </span><span style="color: green">--The Canyon Peak sells bikes
    </span><span style="color: gray">and </span>PP<span style="color: gray">.</span>ProductPhotoID <span style="color: gray">&gt; </span>1 <span style="color: green">--I don't want NO IMAGE AVAILABLE
</span><span style="color: blue">UNION </span><span style="color: gray">ALL
</span><span style="color: blue">SELECT </span><span style="color: red">'Great Falls Soft' </span><span style="color: blue">as </span>Company<span style="color: gray">, </span><span style="color: red">'GreatFallsSoft_logo.png' </span>CompanyLogo<span style="color: gray">,
    </span><span style="color: red">'Great Falls Soft uses only the softest tissues available for those sporting clothes.  And on top of that, they''re waterproof.' </span>CompanyDescription<span style="color: gray">,
    </span>P<span style="color: gray">.</span>Name <span style="color: blue">as </span>Product<span style="color: gray">, </span>PS<span style="color: gray">.</span>Name <span style="color: blue">as </span>Subcategory<span style="color: gray">, </span>PC<span style="color: gray">.</span>Name <span style="color: blue">as </span>Category<span style="color: gray">,
    </span>PP<span style="color: gray">.</span>LargePhoto<span style="color: gray">, </span>P<span style="color: gray">.</span>ListPrice<span style="color: gray">, </span>P<span style="color: gray">.</span><span style="color: blue">Weight</span><span style="color: gray">, </span>P<span style="color: gray">.</span>Size<span style="color: gray">,
    </span>P<span style="color: gray">.</span>SizeUnitMeasureCode<span style="color: gray">, </span>P<span style="color: gray">.</span>WeightUnitMeasureCode
<span style="color: blue">FROM </span>Production<span style="color: gray">.</span>Product <span style="color: blue">AS </span>P
    <span style="color: gray">INNER JOIN </span>Production<span style="color: gray">.</span>ProductSubcategory <span style="color: blue">AS </span>PS
        <span style="color: blue">ON </span>PS<span style="color: gray">.</span>ProductSubcategoryID <span style="color: gray">= </span>P<span style="color: gray">.</span>ProductSubcategoryID
    <span style="color: gray">INNER JOIN </span>Production<span style="color: gray">.</span>ProductCategory <span style="color: blue">AS </span>PC
        <span style="color: blue">ON </span>PC<span style="color: gray">.</span>ProductCategoryID <span style="color: gray">= </span>PS<span style="color: gray">.</span>ProductCategoryID
    <span style="color: gray">LEFT OUTER JOIN </span>Production<span style="color: gray">.</span>ProductProductPhoto PPP
        <span style="color: blue">ON </span>PPP<span style="color: gray">.</span>ProductID <span style="color: gray">= </span>P<span style="color: gray">.</span>ProductID
    <span style="color: gray">LEFT OUTER JOIN </span>Production<span style="color: gray">.</span>ProductPhoto PP
        <span style="color: blue">ON </span>PPP<span style="color: gray">.</span>ProductPhotoID <span style="color: gray">= </span>PP<span style="color: gray">.</span>ProductPhotoID
<span style="color: blue">WHERE </span>PC<span style="color: gray">.</span>Name <span style="color: gray">= </span><span style="color: red">'Clothing' </span><span style="color: green">--Great Falls Soft sells clothes, waterstopping soft clothes
    </span><span style="color: gray">and </span>PP<span style="color: gray">.</span>ProductPhotoID <span style="color: gray">&gt; </span>1 <span style="color: green">--I don't want NO IMAGE AVAILABLE
</span><span style="color: blue">ORDER BY </span>Category <span style="color: blue">asc</span><span style="color: gray">, </span>Subcategory <span style="color: blue">asc</span><span style="color: gray">, </span>Product <span style="color: blue">asc</span><span style="color: gray">;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>I’m not going into the details of this query.&#160; Let’s just say that I’m manipulating data from the database in combination with some hardcoded data to get usable data for our example.&#160; I’ve added some comments to make it clear what the query is doing.&#160; If you have a look at its output, you’ll see that it produces a list of products with some additional fields.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image303.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Results of the query" border="0" alt="Results of the query" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb71.png" width="700" height="72" /></a> </p>
<h2>Different Ways Of Adding Images</h2>
<p>To get started, open up a SSRS solution, add a new report, add a data source connecting to your AdventureWorks 2008 R2 DB, and add a dataset using the above query.</p>
<h3>Embedding Images In Your Report</h3>
<p>The first way of adding images to a report that we’ll take a look at is by embedding them inside the report.&#160; Looking at the scenario requirements described earlier, this is requirement 1.</p>
<p>Let’s add a header to the report.&#160; In the BIDS menu, select <strong>Report</strong> &gt; <strong>Add Page Header</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Adding a header to a report" border="0" alt="Adding a header to a report" src="http://blog.hoegaerden.be/wp-content/uploads/image304.png" width="265" height="178" /> </p>
<p>If you don’t see the Report menu item, you probably have not selected your report.&#160; Click your report in the Design view to select it.</p>
<p>From the Toolbox, drag the Image report item onto the header portion of the report.&#160; Doing that will show a pop-up window, the Image Properties.&#160; By default, the <strong>Select the image source </strong>combobox is set to <em>Embedded</em>.&#160; Good, that’s what we need at this point.&#160; What we now need to do is import an image into the report, using the <strong>Import</strong> button.</p>
<p>Clicking the Import button shows a common file Open dialog.&#160; Our marketing department has given me two images for use in the header: Cloudy_banner.png and AnotherCloudy_banner.png.&#160; Let’s select the first one.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Adding an image to a report by using the Import button on the Image Properties window" border="0" alt="Adding an image to a report by using the Import button on the Image Properties window" src="http://blog.hoegaerden.be/wp-content/uploads/image305.png" width="625" height="434" /> </p>
<p>If you don’t see any images, have a look at that filter dropdown as highlighted in the screenshot above.&#160; By default this is set to JPEG files.</p>
<p>Here’s the result in the Image Properties:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Image Properties with an image selected" border="0" alt="Image Properties with an image selected" src="http://blog.hoegaerden.be/wp-content/uploads/image306.png" width="585" height="532" /> </p>
<p>On the Size page, select <em>Clip</em> instead of <em>Fit proportional</em>.&#160; This is a setting that you’ll need to look at case per case.&#160; For our header images, <em>Clip</em> is the most suitable option.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Image Properties: set Display to Clip" border="0" alt="Image Properties: set Display to Clip" src="http://blog.hoegaerden.be/wp-content/uploads/image307.png" width="585" height="532" /> </p>
<p>Close the Image Properties window and enlarge the image placeholder so that it occupies the whole header area:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Image added to report header" border="0" alt="Image added to report header" src="http://blog.hoegaerden.be/wp-content/uploads/image308.png" width="544" height="180" /> </p>
<p>As you can see, we now have an image in the header.&#160; But we haven’t fully implemented the requirement yet.&#160; The even pages should display a different image than the uneven ones.</p>
<p>To be able to do that, we’ll first add the second banner image to the report.&#160; In the Report Data pane, locate the <em>Images</em> node and open it up.&#160; You’ll notice that the image that we inserted earlier can be found here.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The Images node in the Report Data pane shows all embedded images" border="0" alt="The Images node in the Report Data pane shows all embedded images" src="http://blog.hoegaerden.be/wp-content/uploads/image309.png" width="168" height="159" /> </p>
<p>Right-click the <em>Images</em> node and select <strong>Add Image</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Right-click Images node to add an embedded image to the report" border="0" alt="Right-click Images node to add an embedded image to the report" src="http://blog.hoegaerden.be/wp-content/uploads/image310.png" width="229" height="155" /> </p>
<p>That opens up the familiar file Open dialog which was used to add the first image.&#160; So I’m now selecting the file called AnotherCloudy_banner.png, after changing the default filter to PNG.&#160; After clicking OK, the image gets added under the Images node.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Second banner image added to the report" border="0" alt="Second banner image added to the report" src="http://blog.hoegaerden.be/wp-content/uploads/image311.png" width="190" height="64" />&#160; </p>
<p>With the second image added, all that remains to be done is tell the header that it should pick different images depending on the page number.</p>
<p>Right-click the image in the header and select <strong>Image Properties</strong>.&#160; On the General page, when you click the dropdown of the setting called Use this image, you’ll notice that there are two values now.&#160; These are the same values as displayed in the Report Data pane.&#160; And these are the values to be used in the expression that we’ll create to rotate the images depending on page number.</p>
<p>Click the fx button next to the dropdown and enter the following expression:</p>
<pre class="code">=IIF(Globals!PageNumber <span style="color: blue">Mod </span>2 = 0, <span style="color: #a31515">&quot;Cloudy_banner&quot;</span>, <span style="color: #a31515">&quot;AnotherCloudy_banner&quot;</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>This is a fairly simple expression, using the Mod operator and the IIF() function.&#160; When page number can be divided by two, which means it’s an even page number, Cloudy_banner is displayed.&#160; Otherwise the other banner is displayed.</p>
<p>That’s it, the report header is finished.&#160; When you have a look at the report in Preview, it should now show the second banner on the first page – this is an uneven page.</p>
<p>To conclude this chapter I’d like to mention that this method is usually not the preferred one.&#160; A <strong>disadvantage</strong> here is that the images are stored inside the report RDL and thus cannot be modified without altering the report itself.</p>
<p>Here’s the evidence:</p>
<pre class="code"> <span style="color: blue">&lt;</span><span style="color: #a31515">EmbeddedImages</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">EmbeddedImage </span><span style="color: red">Name</span><span style="color: blue">=</span>&quot;<span style="color: blue">Cloudy_banner</span>&quot;<span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">MIMEType</span><span style="color: blue">&gt;</span>image/png<span style="color: blue">&lt;/</span><span style="color: #a31515">MIMEType</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">ImageData</span><span style="color: blue">&gt;</span>iVBORw0KGgoAAAANSUhEUgAABVsAAABaCAIAAA...</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>To have a look at the RDL yourself, just right-click the report in the <strong>Solution Explorer</strong> and select <em>View Code</em>.</p>
<p>On to requirement number two!</p>
<h3>Displaying Images Through A URL</h3>
<p>At the moment, the report body is still empty, so drag a Table onto it.&#160; Put the Table in the upper-left corner, remove one of the columns so that two remain, remove the Header row and make it a bit wider.</p>
<p>Now set the <strong>DataSetName</strong> property of the Tablix to the name of your dataset, in my case that’s <em>dsProducts</em>.</p>
<p>The report should display the data grouped on company, so right-click on the line that says <em>Details</em> in the Row Groups window part at the bottom of the Design View.&#160; Select <strong>Add Group &gt; Parent Group</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Right-click the Details line in Row Groups to add a new parent group" border="0" alt="Right-click the Details line in Row Groups to add a new parent group" src="http://blog.hoegaerden.be/wp-content/uploads/image312.png" width="646" height="160" /> </p>
<p>Group by Company and add a group header:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Tablix grouping" border="0" alt="Tablix grouping" src="http://blog.hoegaerden.be/wp-content/uploads/image313.png" width="451" height="201" /> </p>
<p>Remove the extra first column that just got generated:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Remove unwanted column" border="0" alt="Remove unwanted column" src="http://blog.hoegaerden.be/wp-content/uploads/image314.png" width="646" height="189" /> </p>
<p>We’ve now got an empty tablix with two columns, a Details row and a Company header row.&#160; In our dataset, one of the fields is called <em>CompanyDescription</em>.&#160; Hover the mouse pointer above the textbox in the top-right, click the small icon that appears and choose the field from the dropdown that appears when you click the icon.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Click the small icon to get a list of fields" border="0" alt="Click the small icon to get a list of fields" src="http://blog.hoegaerden.be/wp-content/uploads/image315.png" width="299" height="64" /> </p>
<p>To add the company’s logo, drag an Image from the Toolbox pane into the textbox on the left of the company description.&#160; Doing this opens up the by now familiar Image Properties dialog.</p>
<p>Give it a good name, such as CompanyLogo, and select <em>External</em> as image source.</p>
<p>Click the fx button next to the <strong>Use this image</strong> box and enter an expression such as this one:</p>
<pre class="code">=<span style="color: #a31515">&quot;file:C:\vavr\test\&quot; </span>+ Fields!CompanyLogo.Value</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>When using External as image source, the image expression should result in a valid URL, any valid URL.&#160; In my example the files are located in a local folder called c:\vavr\test.&#160; Keep in mind that, when you deploy the report to a server, the images should by located in that same folder, this time located on the server.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The Image Properties configured to display an External image" border="0" alt="The Image Properties configured to display an External image" src="http://blog.hoegaerden.be/wp-content/uploads/image316.png" width="417" height="200" /> </p>
<p>By default the image gets displayed using the <em>Fit Proportional </em>setting.&#160; You can verify this in the <strong>Size</strong> page of the Image Properties.&#160; We want the image to get fully displayed while maintaining the aspect ratio, so leave the setting as it is.&#160; Close the image properties dialog.</p>
<p>Vertically enlarge the first row in our tablix to an acceptable size.&#160; In my case the marketing department specified to use a height of 1.5 inches for the company logo.&#160; With the image selected, locate the Size &gt; Height property and set it to “1,5in”.&#160; Note that the decimal separator used here depends on your local settings.</p>
<p>Now have a look at the report in Preview:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The report with company logos added" border="0" alt="The report with company logos added" src="http://blog.hoegaerden.be/wp-content/uploads/image317.png" width="664" height="328" /> </p>
<p>Note that I’ve removed the borders of all textboxes by setting their <strong>BorderStyle </strong>property to <em>None</em>.</p>
<p>With the logo images implemented we have fulfilled requirement two.&#160; On to number three.</p>
<h3>Retrieving Images From The Database</h3>
<p>In this last requirement we’ll have a look at displaying images that are retrieved from the database, also known as data-bound images.</p>
<p>The retrieving part is actually already implemented.&#160; In our dataset there’s a field called <strong>LargePhoto</strong>, that one contains a picture of the product.</p>
<p>Let’s add some product details and a picture in that remaining blank row.&#160; To get full control over layout I want to make the detail part of the tablix a freestyle part.&#160; First merge the two cells together by selecting both of them, then right-click and choose <strong>Merge Cells</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Merging two cells together in a tablix" border="0" alt="Merging two cells together in a tablix" src="http://blog.hoegaerden.be/wp-content/uploads/image318.png" width="686" height="632" /> </p>
<p>Now select a <strong>Rectangle</strong> in the Toolbox pane and drop it into the merged area.&#160; To add fields such as Subcategory and Product you can just select them from the <strong>Report Data </strong>pane and drop them inside the rectangle.&#160; I’m also adding some additional labels and fields, as shown in the next screenshot.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The product details in Design view" border="0" alt="The product details in Design view" src="http://blog.hoegaerden.be/wp-content/uploads/image319.png" width="347" height="196" /> </p>
<p>As you can see I’ve modified the fonts a bit.&#160; The rendered version:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The rendered product details" border="0" alt="The rendered product details" src="http://blog.hoegaerden.be/wp-content/uploads/image320.png" width="306" height="187" /> </p>
<p>This is the expression used for displaying the weight:</p>
<pre class="code">=IIF(
    IsNothing(Fields!Weight.Value),
    <span style="color: #a31515">&quot;unknown&quot;</span>,
    Fields!Weight.Value &amp; <span style="color: #a31515">&quot; &quot; </span>&amp; Fields!WeightUnitMeasureCode.Value
)</pre>
<p><a href="http://11011.net/software/vspaste"></a>And here’s the expression for the size field:</p>
<pre class="code">=Fields!Size.Value &amp; <span style="color: #a31515">&quot; &quot; </span>&amp; Fields!SizeUnitMeasureCode.Value</pre>
<p><a href="http://11011.net/software/vspaste"></a>For the layout the price field I’ve just entered C in the <strong>Format</strong> property of the textbox.</p>
<p>With the textual product details completed, all that remains to be done is adding the product image.</p>
<p>From the Toolbox pane, drag an <strong>Image</strong> into the remaining whitespace in the rectangle, next to the product details.&#160; (You did keep some space available, right?)</p>
<p>Again we get the familiar Image Properties popup.&#160; Give it a good name, like ProductImage, and select the image source that we haven’t used yet, <em>Database</em>.&#160; In the <strong>Use this field </strong>dropdown, select <em>LargePhoto</em>, and select <em>image/gif</em> as <strong>MIME type</strong>.</p>
<p><strong>Note:</strong> the images are stored as GIF.&#160; You can verify this by running a select on the Production.ProductPhoto table.&#160; Looking at the LargePhotoFileName field we see that the extension is .gif.</p>
<p>There one textbox on the General page that’s still blank.&#160; That one is called Tooltip.&#160; Click the fx button next to it and enter following formula:</p>
<pre class="code">=Fields!Product.Value</pre>
<p><a href="http://11011.net/software/vspaste"></a>Click sufficient OK buttons until the properties dialog is gone, then resize the image placeholder so that it occupies the remaining whitespace.</p>
<p>Here’s what the result looks like in preview:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The final report, with a tooltip on the product image" border="0" alt="The final report, with a tooltip on the product image" src="http://blog.hoegaerden.be/wp-content/uploads/image321.png" width="656" height="344" /> </p>
<p>When hovering the mouse pointer above the product image, you’ll get a nice tooltip.</p>
<h2>Conclusion</h2>
<p>In this article I have illustrated the three possible methods of adding an image to your Reporting Services report.</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="Adding Images to a Report" href="http://msdn.microsoft.com/en-us/library/ms156482.aspx" target="_blank">BOL: Adding Images to a Report</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2010/07/07/put-some-images-on-those-ssrs-reports/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Aggregating Data With The OVER Clause</title>
		<link>http://blog.hoegaerden.be/2010/06/01/aggregating-data-with-the-over-clause/</link>
		<comments>http://blog.hoegaerden.be/2010/06/01/aggregating-data-with-the-over-clause/#comments</comments>
		<pubDate>Tue, 01 Jun 2010 21:12:01 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[T-SQL]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2010/06/01/aggregating-data-with-the-over-clause/</guid>
		<description><![CDATA[In this article I will show you a couple of different T-SQL queries to fetch aggregated data.  The main purpose is to illustrate how the OVER clause can be used to aggregate data.
For the examples I will use data from the AdventureWorks2008R2 database, available at CodePlex.
The Data
The AdventureWorks 2008 R2 database contains a view called [...]]]></description>
			<content:encoded><![CDATA[<p>In this article I will show you a couple of different T-SQL queries to fetch aggregated data.  The main purpose is to illustrate how the OVER clause can be used to aggregate data.</p>
<p>For the examples I will use data from the AdventureWorks2008R2 database, <a title="AdventureWorks 2008R2 RTM" href="http://msftdbprodsamples.codeplex.com/releases/view/45907" target="_blank">available at CodePlex</a>.</p>
<h2>The Data</h2>
<p>The AdventureWorks 2008 R2 database contains a view called <em>Sales.vSalesPerson</em>.  This is the data with which I’ll be working in the examples below.  Here’s what it looks like:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image286.png"><img style="display: inline; border-width: 0px;" title="My Working Data" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb68.png" border="0" alt="My Working Data" width="700" height="184" /></a></p>
<p>I’ve hidden some fields so that all the relevant ones are in view.</p>
<h2>The Scenario<a href="http://11011.net/software/vspaste"></a></h2>
<p>Your manager has asked you to create one query, to be executed on the <em>Sales.vSalesPerson</em> table, that returns a list of:</p>
<ul>
<li>all employees (FirstName, LastName, JobTitle, CountryRegionName, StateProvinceName, City),</li>
<li>their sales of last year (SalesLastYear),</li>
<li>the sum of the sales of last year for their country,</li>
<li>the average of the sales of last year compared to all employees with the same type of phone (PhoneNumberType)</li>
<li>the overall average and sum of the sales of last year.</li>
</ul>
<h3>Using Derived Tables</h3>
<p>No problem you say, coming right up.  So you start building your query, retrieving all fields as requested.</p>
<p>After quite some typing, here’s what your query looks like:</p>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue;">select </span>S<span style="color: gray;">.</span>FirstName<span style="color: gray;">, </span>S<span style="color: gray;">.</span>LastName<span style="color: gray;">, </span>S<span style="color: gray;">.</span>JobTitle<span style="color: gray;">, </span>S<span style="color: gray;">.</span>PhoneNumberType<span style="color: gray;">, </span>S<span style="color: gray;">.</span>CountryRegionName<span style="color: gray;">,
    </span>S<span style="color: gray;">.</span>StateProvinceName<span style="color: gray;">, </span>S<span style="color: gray;">.</span>City<span style="color: gray;">, </span>S<span style="color: gray;">.</span>SalesLastYear<span style="color: gray;">,
    </span>GeographicSales<span style="color: gray;">.</span>SalesLastYearGeographic_SUM<span style="color: gray;">,
    </span>SalesByPhoneType<span style="color: gray;">.</span>SalesLastYearByPhoneNumberType_AVG<span style="color: gray;">,
    </span>SalesSUM<span style="color: gray;">.</span>SalesLastYear_AVG<span style="color: gray;">, </span>SalesSUM<span style="color: gray;">.</span>SalesLastYear_SUM
<span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson S
<span style="color: green;">--Derived Table 1: the overall aggregates
</span><span style="color: gray;">cross join (
    </span><span style="color: blue;">select </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span>SalesLastYear_SUM<span style="color: gray;">, </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span>SalesLastYear_AVG
    <span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson
<span style="color: gray;">) </span>SalesSUM
<span style="color: green;">--Derived Table 2: the aggregate on Country level
</span><span style="color: gray;">inner join (
    </span><span style="color: blue;">select </span>CountryRegionName<span style="color: gray;">, </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span>SalesLastYearGeographic_SUM
    <span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson
    <span style="color: blue;">group by </span>CountryRegionName
<span style="color: gray;">) </span>GeographicSales <span style="color: blue;">on </span>GeographicSales<span style="color: gray;">.</span>CountryRegionName <span style="color: gray;">= </span>S<span style="color: gray;">.</span>CountryRegionName
<span style="color: green;">--Derived Table 3: the aggregate on phone type
</span><span style="color: gray;">inner join (
    </span><span style="color: blue;">select </span>PhoneNumberType<span style="color: gray;">, </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span>SalesLastYearByPhoneNumberType_AVG
    <span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson
    <span style="color: blue;">group by </span>PhoneNumberType
<span style="color: gray;">) </span>SalesByPhoneType <span style="color: blue;">on </span>SalesByPhoneType<span style="color: gray;">.</span>PhoneNumberType<span style="color: gray;">= </span>S<span style="color: gray;">.</span>PhoneNumberType<span style="color: gray;">;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>The main query is retrieving all fields as requested.  Further down there are three derived table queries, each one retrieving aggregates on a different level.</p>
<p>The first derived table is retrieving the overall aggregates.  These are cross-joined with every record in our main query so for each record the totals will be the same, which is what we want.</p>
<p>The second derived table retrieves the aggregates on Country level, including the CountryRegionName.  This is done using the conventional GROUP BY method.  The CountryRegionName is the key on which the derived table is joined to the main table.</p>
<p>The third derived table uses a similar system, this time for the aggregate on phone type.</p>
<p>And here’s the query’s output:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image287.png"><img style="display: inline; border-width: 0px;" title="Output of the query using subqueries" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb69.png" border="0" alt="Output of the query using subqueries" width="700" height="174" /></a></p>
<p>Happy with this result, you go up to the cafeteria to finally have lunch with your colleagues (who left 15 minutes earlier but you wanted to get your query finished first).</p>
<h3>Using The OVER Clause</h3>
<p>During lunch you explain to your peers what kind of funny request you got from management and told them how you solved it.</p>
<p>Then one of them speaks up and says: “Want to know how you can avoid all that typing?  Use the OVER clause!  I’ll show you when we are back at our desks.”</p>
<p>After lunch, here’s what your colleague helps to produce:</p>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue;">select </span>S<span style="color: gray;">.</span>FirstName<span style="color: gray;">, </span>S<span style="color: gray;">.</span>LastName<span style="color: gray;">, </span>S<span style="color: gray;">.</span>JobTitle<span style="color: gray;">, </span>S<span style="color: gray;">.</span>PhoneNumberType<span style="color: gray;">, </span>S<span style="color: gray;">.</span>CountryRegionName<span style="color: gray;">,
    </span>S<span style="color: gray;">.</span>StateProvinceName<span style="color: gray;">, </span>S<span style="color: gray;">.</span>City<span style="color: gray;">, </span>S<span style="color: gray;">.</span>SalesLastYear<span style="color: gray;">,
    </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span>CountryRegionName<span style="color: gray;">)
        </span>SalesLastYearGeographic_SUM<span style="color: gray;">,
    </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span>PhoneNumberType<span style="color: gray;">)
        </span>SalesLastYearByPhoneNumberType_AVG<span style="color: gray;">,
    </span>SalesSUM<span style="color: gray;">.</span>SalesLastYear_AVG<span style="color: gray;">, </span>SalesSUM<span style="color: gray;">.</span>SalesLastYear_SUM
<span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson S
<span style="color: green;">--Derived Table 1: the overall aggregates
</span><span style="color: gray;">cross join (
    </span><span style="color: blue;">select </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span>SalesLastYear_SUM<span style="color: gray;">, </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span>SalesLastYear_AVG
    <span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson
<span style="color: gray;">) </span>SalesSUM<span style="color: gray;">;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>As you can see, derived tables 2 and 3 are gone.  They have been replaced with <a title="OVER Clause (Transact-SQL)" href="http://msdn.microsoft.com/en-us/library/ms189461.aspx" target="_blank">the OVER clause</a>, in combination with PARTITION BY.  What you say with the OVER clause is: “partition the dataset by the fields specified in the PARTITION BY and apply the aggregation on those partitions”.  Another word for this is <strong>aggregate window function</strong>.</p>
<p>As you like the approach, you ask your co-worker how you can get rid of that cross join.  He doesn’t really know but then another colleague who overheard your conversation says: “On this blog the other day I read that you can use the OVER clause and partition by anything you want.  As long as it’s a constant, it will work!”.</p>
<p>So you give that a try and you end up with the following final query:</p>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue;">select </span>FirstName<span style="color: gray;">, </span>LastName<span style="color: gray;">, </span>JobTitle<span style="color: gray;">, </span>PhoneNumberType<span style="color: gray;">, </span>CountryRegionName<span style="color: gray;">,
    </span>StateProvinceName<span style="color: gray;">, </span>City<span style="color: gray;">, </span>SalesLastYear<span style="color: gray;">,
    </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span>CountryRegionName<span style="color: gray;">)
        </span>SalesLastYearGeographic_SUM<span style="color: gray;">,
    </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span>PhoneNumberType<span style="color: gray;">)
        </span>SalesLastYearByPhoneNumberType_AVG<span style="color: gray;">,
    </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span><span style="color: red;">'duh'</span><span style="color: gray;">) </span>SalesLastYear_AVG<span style="color: gray;">,
    </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span>1<span style="color: gray;">) </span>SalesLastYear_SUM
<span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson<span style="color: gray;">;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>As illustrated in the example, you can use any constant value to calculate overall aggregates over the whole dataset using the OVER clause.</p>
<p>You happily thank your colleagues and tell them that next time you’ll be able to join them for lunch on time.</p>
<p>About a week later you’re explaining to one of your friends how you’ve gotten to know the OVER clause. After hearing how you use it to aggregate over the whole dataset, he smiles and says: “I know how you can simplify it even more! Don’t partition at all!”.</p>
<p>Taking a closer look it turns out that the PARTITION BY is actually optional:</p>
<pre>Ranking Window Functions
&lt; OVER_CLAUSE &gt; :: =     OVER ( [ PARTITION BY value_expression, ... [ n ] ]            &lt;ORDER BY_Clause&gt; )Aggregate Window Functions
&lt; OVER_CLAUSE &gt; :: =     OVER ( [ PARTITION BY value_expression, ... [ n ] ] )</pre>
<p>See those square brackets? Means it’s optional.</p>
<p>So here is the real final query:</p>
<pre class="code"><span style="color: blue;">select </span>FirstName<span style="color: gray;">, </span>LastName<span style="color: gray;">, </span>JobTitle<span style="color: gray;">, </span>PhoneNumberType<span style="color: gray;">, </span>CountryRegionName<span style="color: gray;">,
    </span>StateProvinceName<span style="color: gray;">, </span>City<span style="color: gray;">, </span>SalesLastYear<span style="color: gray;">,
    </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span>CountryRegionName<span style="color: gray;">)
        </span>SalesLastYearGeographic_SUM<span style="color: gray;">,
    </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">(</span><span style="color: blue;">PARTITION BY </span>PhoneNumberType<span style="color: gray;">)
        </span>SalesLastYearByPhoneNumberType_AVG<span style="color: gray;">,
    </span><span style="color: magenta;">AVG</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">() </span>SalesLastYear_AVG<span style="color: gray;">,
    </span><span style="color: magenta;">SUM</span><span style="color: gray;">(</span>SalesLastYear<span style="color: gray;">) </span><span style="color: blue;">OVER </span><span style="color: gray;">() </span>SalesLastYear_SUM
<span style="color: blue;">from </span>Sales<span style="color: gray;">.</span>vSalesPerson<span style="color: gray;">;
</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<h2>Conclusion</h2>
<p>When you compare the final query with the first one, tell me, which one would you prefer to maintain?  Do you prefer to have lunch with your peers or to arrive late and miss all the fun?</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="The OVER Clause (Transact-SQL)" href="http://msdn.microsoft.com/en-us/library/ms189461.aspx" target="_blank">OVER Clause (Transact-SQL)</a></p>
<p><a title="Join Fundamentals" href="http://msdn.microsoft.com/en-us/library/ms191517.aspx" target="_blank">Join Fundamentals</a></p>
<p><a title="SELECT (Transact-SQL)" href="http://msdn.microsoft.com/en-us/library/ms189499.aspx" target="_blank">SELECT (Transact-SQL)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2010/06/01/aggregating-data-with-the-over-clause/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Implementing Data Bars In A Grouped Table</title>
		<link>http://blog.hoegaerden.be/2010/05/27/implementing-data-bars-in-a-grouped-table/</link>
		<comments>http://blog.hoegaerden.be/2010/05/27/implementing-data-bars-in-a-grouped-table/#comments</comments>
		<pubDate>Thu, 27 May 2010 20:16:21 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Reporting Services 2008 R2]]></category>
		<category><![CDATA[SQL Server 2008 R2]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2010/05/27/implementing-data-bars-in-a-grouped-table/</guid>
		<description><![CDATA[Earlier I wrote an article about the new lookup functions that ship with SQL Server 2008 R2.  Today I’m going to show you another new feature of SSRS 2008 R2, this time in the visualization department.  This feature is the Data Bar.  With this new component it’s fairly easy to make your tabular data a [...]]]></description>
			<content:encoded><![CDATA[<p>Earlier I wrote an article about <a title="Looking Up Data On Different Sources" href="http://blog.hoegaerden.be/2010/05/16/looking-up-data-on-different-sources/">the new lookup functions</a> that ship with SQL Server 2008 R2.  Today I’m going to show you another new feature of SSRS 2008 R2, this time in the visualization department.  This feature is the <a title="BOL 2008R2: Sparklines and Data Bars" href="http://msdn.microsoft.com/en-us/library/ee636365%28v=SQL.105%29.aspx" target="_blank">Data Bar</a>.  With this new component it’s fairly easy to make your tabular data a lot more visual, and thus easier to interpret.  And here’s how to do it.</p>
<p>I’ll be starting from the report that I created in <a title="Your First OLAP Report" href="http://blog.hoegaerden.be/2010/01/24/your-first-olap-report/">Your First OLAP Report</a>.  That allows me to focus on the visualization part, without first needing to build a table report.  (Okay, I admit, it’s not 100% the same report – I’ve modified the colors a bit because I felt the green was too dark.) But obviously this method will work with any report that’s showing data in a table.</p>
<p>Furthermore I’m running SQL Server 2008 R2 Nov CTP, 64-bit, and I’m using the BIDS to develop the report.</p>
<p>The final result <a title="Download: &quot;First OLAP Report With Data Bars&quot;" href="http://cid-81c8b064cbbe1698.skydrive.live.com/self.aspx/.Public/blog/FirstOLAPReportWithDataBars.rdl" target="_blank">can be downloaded from Skydrive here</a>.</p>
<h2>Implementing The Data Bar</h2>
<p>The report that we’re using is showing some sales figures grouped in three levels: Country, State/Province and City.  We’re going to add an extra column on the right of the table to contain the data bar.  Let’s first explore the Toolbox pane to discover the new visualization report items.</p>
<p><img style="display: inline; border-width: 0px;" title="The new Reporting Services 2008 R2 report items: Map, Data Bar, Sparkline and Indicator" src="http://blog.hoegaerden.be/wp-content/uploads/image262.png" border="0" alt="The new Reporting Services 2008 R2 report items: Map, Data Bar, Sparkline and Indicator" width="120" height="342" /></p>
<p>The new items have been highlighted in yellow.  As you can see, besides <strong>Data Bar </strong>there’s also <strong>Sparkline, </strong><strong>Map </strong>and <strong>Indicator</strong>.  But those are not on topic now.</p>
<p>To add a Data Bar, simply drag it from the Toolbox into a textbox on the report.  Doing that will show the following popup window:</p>
<p><img style="display: inline; border-width: 0px;" title="Select Data Bar Type window" src="http://blog.hoegaerden.be/wp-content/uploads/image263.png" border="0" alt="Select Data Bar Type window" width="348" height="482" /></p>
<p>From left to right, there’s Bar, Stacked Bar and 100% Stacked Bar.  And those are also available in vertical direction, Column.  I’m going to use the regular Bar as highlighted in the screenshot.</p>
<p>The Data Bar has now been added to the report, but it doesn’t do anything yet.  We first need to tell it what data to visualize.  Clicking it once will select it, clicking it once more will show us the following <strong>Chart Data </strong>popup:</p>
<p><img style="display: inline; border-width: 0px;" title="Data Bar: Chart Data" src="http://blog.hoegaerden.be/wp-content/uploads/image264.png" border="0" alt="Data Bar: Chart Data" width="612" height="434" /></p>
<p>Click the plus icon to get a drop-down of fields in the dataset.  Select the numeric field that you want to visualize, in my case that’s the Reseller_Sales_Amount.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image265.png"><img style="display: inline; border-width: 0px;" title="Data Bar: Chart Data with Reseller_Sales_Amount selected=" border="0" alt="Data Bar: Chart Data with Reseller_Sales_Amount selected=" height="366" /></a></p>
<p>By default, the aggregation used on the data is Sum.  But there are other options as well, have a look at the dropdown next to the [Sum(Reseller_Sales…  In the example here I’m going to keep the Sum.</p>
<p><img style="display: inline; border-width: 0px;" title="Other aggregation functions of the Data Bar" src="http://blog.hoegaerden.be/wp-content/uploads/image266.png" border="0" alt="Other aggregation functions of the Data Bar" width="437" height="450" /></p>
<p>The report Preview looks like this:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image267.png"><img style="display: inline; border: 0px;" title="Report preview with the data bar" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb63.png" border="0" alt="Report preview with the data bar" width="700" height="208" /></a></p>
<p>In this report we can easily see what states have got a higher sales amount: those with the longer bars.</p>
<p>Let’s add bars for the Country level as well.  There are two ways to achieve that: you can either drag a new Data Bar onto the report or you can just copy/paste the textbox containing our first Data Bar.</p>
<p>To make the report easier to read I will change the color of the Data Bar to the color of the group’s background.  Setting up the color of the Data Bar is done as follows: select the Data Bar so that you get the Chart Data popup.  In the Properties pane you should see that the Chart Series is selected.  Then right-click on the bar and select <strong>Series Properties</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="The right-click menu on the Data Bar." src="http://blog.hoegaerden.be/wp-content/uploads/image268.png" border="0" alt="The right-click menu on the Data Bar." width="434" height="445" /></p>
<p>In the <strong>Series Properties</strong> window, select the <strong>Fill</strong> page and select your favorite color.  If you want you can also use a gradient fill or pattern.  You can even use a Switch statement and color them differently depending on their value, similar to the method that I used in my <a title="SSRS and MDX: Detecting Missing Fields" href="http://blog.hoegaerden.be/2009/07/06/ssrs-and-mdx-detecting-missing-fields/">SSRS and MDX: Detecting Missing Fields</a> article.  Well, in short, any expression that you can think of and results in a color will work fine!</p>
<p><img style="display: inline; border-width: 0px;" title="Series Properies: setting up the Fill color" src="http://blog.hoegaerden.be/wp-content/uploads/image269.png" border="0" alt="Series Properies: setting up the Fill color" width="585" height="520" /></p>
<p>With the second data bar and custom coloring set up, here’s the rendered report:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image270.png"><img style="display: inline; border: 0px;" title="Report with data bar on two grouping levels" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb64.png" border="0" alt="Report with data bar on two grouping levels" width="700" height="237" /></a></p>
<p>Hang on, is that correct? As you can see, the data bar for California is longer than the one for Canada while the sales amount for Canada is definitely the higher one.  An even nicer example is United Kingdom with only one state England.  Both amounts are equal yet their data bars are certainly not.</p>
<p>Well, this is because the data bar by default uses the same scope as the group where it’s put.  Canada and United Kingdom are in the Country group and all Country data bars compare nicely to each other.  California and England are in the State/Province group and also compare nicely to each other!</p>
<p>Depending on the report’s requirements this may or may not be the desired effect.  But I wouldn’t be mentioning this if there weren’t any other options, would I?</p>
<h3>Setting The Maximum Value Of The Horizontal Axis</h3>
<p>A correct column label for our current column would be <em>“% of group</em>”.  Let’s add a second column which will show the percentage of the row compared to the total of the dataset, “<em>% of overall total</em>”.  After adding the extra column, copy/paste the data bars from the first column over into the new textboxes in the second column.</p>
<p>To get what we want, we need to tell the data bar that the maximum for the horizontal axis is the total of the dataset and not the total of the grouping level of the table.  So, right-click one of the data bars in the new column and select <strong>Horizontal Axis Properties</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Right-click menu on tablix textbox with a data bar" src="http://blog.hoegaerden.be/wp-content/uploads/image271.png" border="0" alt="Right-click menu on tablix textbox with a data bar" width="545" height="568" /></p>
<p>As you can see, the default for the <em>Maximum</em> value is set to “<em>Auto</em>”.  Note that the name of my tablix is “Tablix1”, as shown in the <em>Align axes in</em> dropdown.</p>
<p><img style="display: inline; border-width: 0px;" title="Horizontal Axis Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image272.png" border="0" alt="Horizontal Axis Properties" width="585" height="530" /></p>
<p>Let’s replace the <em>Auto</em> as <strong>Maximum</strong> with the following expression:</p>
<pre class="code">=Sum(Fields!Reseller_Sales_Amount.Value, <span style="color: #a31515;">"Tablix1"</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>This expression says that we need the sum of the Reseller_Sales_Amount, scoped over the whole tablix.</p>
<p>Having changed the <strong>Maximum</strong> value on both data bars gives us the following preview:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image273.png"><img style="display: inline; border-width: 0px;" title="Report rendered with status bar scoped over whole dataset" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb65.png" border="0" alt="Report rendered with status bar scoped over whole dataset" width="700" height="203" /></a></p>
<p>As you can see, this time around the data bars for England and United Kingdom have gotten the same size.  Bars from different grouping levels can now be compared with each other.</p>
<h3>Showing Labels On The Data Bars</h3>
<p>In this report it would be interesting to add a label that displays the percentage to the status bars, so let’s do that.</p>
<p>For the percentage calculation of the first column of data bars we need to get the total of the current group and divide that by the total of the group one level higher.  For the State/Province level that gives us the following expression:</p>
<pre class="code">=Sum(Fields!Reseller_Sales_Amount.Value)
    / Sum(Fields!Reseller_Sales_Amount.Value, <span style="color: #a31515;">"grpCountry"</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>The grpCountry refers to the name of the grouping one level higher, as shown in following screenshot:</p>
<p><img style="display: inline; border-width: 0px;" title="The groupings as defined on my example tablix" src="http://blog.hoegaerden.be/wp-content/uploads/image274.png" border="0" alt="The groupings as defined on my example tablix" width="680" height="103" /></p>
<p>And for the Country level we need this expression:</p>
<pre class="code">=Sum(Fields!Reseller_Sales_Amount.Value)
    / Sum(Fields!Reseller_Sales_Amount.Value, <span style="color: #a31515;">"Tablix1"</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>The only difference with the previous expression is the scope.</p>
<p>“Ok, so where do I type those expressions?” I hear you think.  Right-click the Data Bar (after first selecting the textbox that contains it) and choose <strong>Show Data Labels</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Show Data Labels in right-click popup on Chart Series" src="http://blog.hoegaerden.be/wp-content/uploads/image275.png" border="0" alt="Show Data Labels in right-click popup on Chart Series" width="309" height="300" /></p>
<p>That adds a label to the chart but we still need to configure it to show the percentage.  By default it uses the value as label.  This can be verified in the <strong>Chart Series </strong>properties:</p>
<p><img style="display: inline; border-width: 0px;" title="Chart Series properties: UseValueAsLabel" src="http://blog.hoegaerden.be/wp-content/uploads/image276.png" border="0" alt="Chart Series properties: UseValueAsLabel" width="287" height="392" /></p>
<p>The <strong>UseValueAsLabel</strong> is set to <em>True</em>, confirming what I just stated.  Furthermore, activating the <strong>Show Data Labels </strong>option also set the <strong>Visible</strong> property to <em>True</em>.  So another way of adding the label is by just setting this property to <em>True</em>.</p>
<p>Let’s now configure that label.  Right-click it and select <strong>Series Label Properties</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Right-click menu on label" src="http://blog.hoegaerden.be/wp-content/uploads/image277.png" border="0" alt="Right-click menu on label" width="275" height="179" /></p>
<p>The General page of the <strong>Series Label Properties </strong>window allows you to define the Label data.  That’s where you need to enter the expression that I mentioned earlier.</p>
<p>After you’ve entered the expression, the BIDS will ask you if you want to set the UseValueAsLabel to False, so click Yes.</p>
<p><img style="display: inline; border-width: 0px;" title="Do you want to set the UseValueAsLabel to False?" src="http://blog.hoegaerden.be/wp-content/uploads/image278.png" border="0" alt="Do you want to set the UseValueAsLabel to False?" width="593" height="540" /></p>
<p>With the label selected as shown in the next screenshot you can use the formatting toolbar buttons to give it a decent font and all.</p>
<p><img style="display: inline; border-width: 0px;" title="Data Bar with Label selected" src="http://blog.hoegaerden.be/wp-content/uploads/image279.png" border="0" alt="Data Bar with Label selected" width="207" height="37" /></p>
<p>For our second column of data bars the expressions need to take into account that we need the percentage as compared to all the data, unrelated to the level.  This actually makes it easier because we can use the same expression on both the State/Province and Country level.  Furthermore, it’s exactly the same expression as the one used on Country level in the first data bar column (i. e. the second expression above) because Country is the highest level.</p>
<p>Let’s have a look at the result in preview:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image280.png"><img style="display: inline; border-width: 0px;" title="Preview of report with labels on data bars" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb66.png" border="0" alt="Preview of report with labels on data bars" width="700" height="185" /></a></p>
<p>Woah, looks like we forgot something doesn’t it?  We forgot to format the label as being a percentage!  There are two ways to get that done: through the <strong>Number</strong> page on the <strong>Series Label Properties </strong>window:</p>
<p><img style="display: inline; border-width: 0px;" title="Series Label Properties: formatting number as percentage" src="http://blog.hoegaerden.be/wp-content/uploads/image281.png" border="0" alt="Series Label Properties: formatting number as percentage" width="585" height="482" /></p>
<p>Or by using the properties with the label selected (the Properties pane should show <strong>Chart Series Labels </strong>in the dropdown on top):</p>
<p><img style="display: inline; border-width: 0px;" title="Chart Series Labels properties" src="http://blog.hoegaerden.be/wp-content/uploads/image282.png" border="0" alt="Chart Series Labels properties" width="297" height="528" /></p>
<p>I’ve opted for a percentage without any decimals.</p>
<p>Let’s have another look at that report:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image283.png"><img style="display: inline; border-width: 0px;" title="The final report with two data bar columns" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb67.png" border="0" alt="The final report with two data bar columns" width="700" height="201" /></a></p>
<p>That sure looks better doesn’t it?  The status bars on the right compare over the grouping levels while those on the left compare with each other within the same group.  And they all have a clear label indicating what they represent.</p>
<p>Have fun putting those data bars on your reports!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="BOL 2008R2: What's New (Reporting Services)" href="http://msdn.microsoft.com/en-us/library/ms170438%28v=SQL.105%29.aspx" target="_blank">BOL 2008R2: What&#8217;s New (Reporting Services)</a></p>
<p><a title="BOL 2008R2: Sparklines and Data Bars" href="http://msdn.microsoft.com/en-us/library/ee636365%28v=SQL.105%29.aspx" target="_blank">BOL 2008R2: Sparklines and Data Bars</a></p>
<p><a title="An Introduction to Data Bars in SQL Server Reporting Services 2008 R2" href="http://blogs.msdn.com/seanboon/archive/2009/11/23/an-introduction-to-data-bars-in-sql-server-reporting-services-2008-r2.aspx" target="_blank">An Introduction to Data Bars in SQL Server Reporting Services 2008 R2</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2010/05/27/implementing-data-bars-in-a-grouped-table/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Looking Up Data On Different Sources</title>
		<link>http://blog.hoegaerden.be/2010/05/16/looking-up-data-on-different-sources/</link>
		<comments>http://blog.hoegaerden.be/2010/05/16/looking-up-data-on-different-sources/#comments</comments>
		<pubDate>Sun, 16 May 2010 12:41:27 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Reporting Services 2008 R2]]></category>
		<category><![CDATA[SQL Server 2008 R2]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2010/05/16/looking-up-data-on-different-sources/</guid>
		<description><![CDATA[Almost a year ago I wrote a small blog post to ask everyone to vote on a certain Connect item related to the linking of two datasets in a Reporting Services report.&#160; At this moment there have been 87 positive votes on the request.
Now that SQL Server 2008 R2 has been RTM’ed, it’s time to [...]]]></description>
			<content:encoded><![CDATA[<p>Almost a year ago I wrote <a title="Want to link datasets? Please vote!" href="http://blog.hoegaerden.be/2009/06/13/want-to-link-datasets-please-vote/">a small blog post</a> to ask everyone to vote on <a title="Merging / Linking datasets on report level (SSRS 2008)" href="https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=419819" target="_blank">a certain Connect item</a> related to the linking of two datasets in a Reporting Services report.&#160; At this moment there have been 87 positive votes on the request.</p>
<p>Now that <a title="Microsoft SQL Server 2008 R2" href="http://www.microsoft.com/sqlserver/2008/en/us/r2.aspx" target="_blank">SQL Server 2008 R2</a> has been RTM’ed, it’s time to demonstrate new functionality in SSRS that allows the retrieval of data from another dataset, a dataset not linked to your data region.&#160; It’s not completely the same as actually joining two datasets, but it’s better than nothing – and it works!</p>
<p>In this article I’ll show you how exactly this works by using the new Lookup, LookupSet and MultiLookup SSRS functions.</p>
<p>I’m using the AdventureWorks 2008R2 relational database and the AdventureWorksDW 2008R2 data warehouse, <a title="AdventureWorks 2008R2 November CTP" href="http://msftdbprodsamples.codeplex.com/releases/view/24854" target="_blank">available from CodePlex</a>.&#160; The main data is coming from the data warehouse while all the lookups are done on the relational database.</p>
<h2>Setting Up A Basic Table Report</h2>
<p>In my report I’ve created a dataset called dsInternetSales.&#160; This dataset is retrieving data from the AdventureWorksDW2008R2 data warehouse using the following query:</p>
<pre class="code"><span style="color: blue">select </span>PROD<span style="color: gray">.</span>EnglishProductName<span style="color: gray">, </span>PROD<span style="color: gray">.</span>ProductAlternateKey<span style="color: gray">, </span>PROD<span style="color: gray">.</span>ListPrice<span style="color: gray">,
    </span>PSC<span style="color: gray">.</span>EnglishProductSubcategoryName<span style="color: gray">, </span>PC<span style="color: gray">.</span>EnglishProductCategoryName<span style="color: gray">,
    </span>S<span style="color: gray">.</span>OrderQuantity<span style="color: gray">, </span>S<span style="color: gray">.</span>SalesAmount
<span style="color: blue">from </span>FactInternetSales S
<span style="color: gray">inner join </span>DimProduct PROD <span style="color: blue">on </span>S<span style="color: gray">.</span>ProductKey <span style="color: gray">= </span>PROD<span style="color: gray">.</span>ProductKey
<span style="color: gray">inner join </span>DimProductSubcategory PSC
    <span style="color: blue">on </span>PROD<span style="color: gray">.</span>ProductSubcategoryKey <span style="color: gray">= </span>PSC<span style="color: gray">.</span>ProductSubcategoryKey
<span style="color: gray">inner join </span>DimProductCategory PC <span style="color: blue">on </span>PSC<span style="color: gray">.</span>ProductCategoryKey <span style="color: gray">= </span>PC<span style="color: gray">.</span>ProductCategoryKey</pre>
<p><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a><a href="http://11011.net/software/vspaste"></a></p>
<p>Using that dataset, I’ve set up a Table as shown in following screenshot.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Basic Table Report" border="0" alt="Basic Table Report" src="http://blog.hoegaerden.be/wp-content/uploads/image249.png" width="630" height="294" /> </p>
<p>The Details group has been set up to group on ProductAlternateKey.&#160; On top of the Details group, I’ve grouped on EnglishProductSubcategoryName and the top-level group is grouping on EnglishProductCategoryName.&#160; The Order Quantity column is displaying the sum of the OrderQuantity values for each ProductAlternateKey.</p>
<p>The result is a report that shows all (internet) sales per product, without any filtering.&#160; Very useful report if you want to know how many items your company has sold since it’s existence.&#160; Okay, management would probably like to see some filtering on here, but that’s not the purpose of this article.</p>
<p>Here’s what it looks like in Preview:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Basic Table Report Rendered" border="0" alt="Basic Table Report Rendered" src="http://blog.hoegaerden.be/wp-content/uploads/image250.png" width="481" height="360" /> </p>
<p>&#160;</p>
<h2>Adding Data From Another Database</h2>
<p>Imagine now that you need to add an extra line under each product, containing the product description.&#160; But this description is not available in the data warehouse.&#160; In fact it could even be stored on another server.</p>
<p>In the example here we will retrieve the description from the AdventureWorks2008R2 relational database.</p>
<h3>Setting Up The Second Dataset</h3>
<p>I’ve created an additional dataset called dsProductInfo, using the following query:</p>
<p><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">select </span>P<span style="color: gray">.</span>ProductNumber<span style="color: gray">, </span>PD<span style="color: gray">.</span><span style="color: blue">Description
from </span>Production<span style="color: gray">.</span>Product P
<span style="color: gray">inner join </span>Production<span style="color: gray">.</span>ProductModel PM <span style="color: blue">on </span>P<span style="color: gray">.</span>ProductModelID <span style="color: gray">= </span>PM<span style="color: gray">.</span>ProductModelID
<span style="color: gray">inner join </span>Production<span style="color: gray">.</span>ProductModelProductDescriptionCulture PMPDC
    <span style="color: blue">on </span>PMPDC<span style="color: gray">.</span>ProductModelID <span style="color: gray">= </span>PM<span style="color: gray">.</span>ProductModelID
    <span style="color: gray">and </span>PMPDC<span style="color: gray">.</span>CultureID <span style="color: gray">= </span><span style="color: red">'en'
</span><span style="color: gray">inner join </span>Production<span style="color: gray">.</span>ProductDescription PD
    <span style="color: blue">on </span>PMPDC<span style="color: gray">.</span>ProductDescriptionID <span style="color: gray">= </span>PD<span style="color: gray">.</span>ProductDescriptionID</pre>
<p><a href="http://11011.net/software/vspaste"></a>Not only does it retrieve the product’s description, we’re also fetching the ProductNumber.&#160; Here’s what part of the result looks like:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Result of product description query" border="0" alt="Result of product description query" src="http://blog.hoegaerden.be/wp-content/uploads/image251.png" width="462" height="153" /> </p>
<p>The reason that we’re retrieving ProductNumber as well is because it matches with the ProductAlternateKey which we’ve retrieved earlier in our first dataset.&#160; And this is very important because that’s the key on which we’re going to link the datasets.</p>
<h3>Using The Lookup Function</h3>
<p>I’ve added an additional row inside the Details group and inserted a <a title="The Power Of The Placeholder" href="http://blog.hoegaerden.be/2009/04/07/the-power-of-the-placeholder/">Placeholder</a> to retrieve the product’s description, using the new <a title="BOL2008R2: Lookup Function" href="http://msdn.microsoft.com/en-us/library/ee210575%28v=SQL.105%29.aspx" target="_blank">Lookup function</a>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Additional row inside Details group" border="0" alt="Additional row inside Details group" src="http://blog.hoegaerden.be/wp-content/uploads/image252.png" width="543" height="150" /> </p>
<p>So, what does the Placeholder’s expression look like?&#160; Here it is:</p>
<pre class="code">=Lookup(
    Fields!ProductAlternateKey.Value,
    Fields!ProductNumber.Value,
    Fields!Description.Value,
    <span style="color: #a31515">&quot;dsProductInfo&quot;
</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a>As you can see, the Lookup function requires four parameters.</p>
<p>The first parameter is the key value in your current dataset, the dataset used by the table data region.&#160; In our case that’s the ProductAlternateKey field in the dsInternetSales dataset.</p>
<p>The second parameter is the name of the key field in the second dataset, the one on which the lookup will happen.&#160; In our case that’s the ProductNumber in the dsProductInfo dataset.</p>
<p>The third parameter is the field from the second dataset that you’re wanting to retrieve using the lookup, in our case the Description field from dsProductInfo.</p>
<p>And finally, the last parameter is the name of the dataset on which you want to do the lookup.</p>
<p>Please note that parameter number four is a string parameter, so the value needs to be enclosed by double quotes.&#160; If you forget about that, you’ll get a couple of nice error messages like these:</p>
<blockquote>
<p>[rsInvalidLookupScope]&#160; The Value expression for the textrun ‘Textbox29.Paragraphs[0].TextRuns[0]’ has a scope parameter that is not valid for a lookup function. The scope parameter must be set to a string constant that is the name of a dataset.</p>
</blockquote>
<p>So, don’t forget the quotes.</p>
<p>With the Lookup call set up as explained, here’s the updated report Preview:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Rendered report with product descriptions added through Lookup" border="0" alt="Rendered report with product descriptions added through Lookup" src="http://blog.hoegaerden.be/wp-content/uploads/image253.png" width="518" height="594" /> </p>
<p>How cool is that huh?&#160; Each product has gotten a description, retrieved from another database, and still in the same table data region.&#160; Before R2 of SQL Server 2008, this wasn’t possible to achieve (well, not easily anyway) and now it’s actually fairly simple!</p>
<p>Is that all?&#160; Ha, I was kinda hoping that you were going to ask that.&#160; No, it’s not all, there are two more new lookup functions: LookupSet and MultiLookup.</p>
<h3>More Lookups: The LookupSet Function</h3>
<p>In case you’re wondering, in the Expression Builder the new lookup functions are located under the Miscellaneous node:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image254.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Expression Builder: the new lookup functions are under Miscellaneous" border="0" alt="Expression Builder: the new lookup functions are under Miscellaneous" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb61.png" width="682" height="231" /></a> </p>
<p>Let’s say that you want to add another detail row, this time it needs to show all colors in which the product is manufactured.&#160; Again this additional info is coming from the AdventureWorks relational database.</p>
<p>I’ve created a dataset called dsProductColors using the following query:</p>
<pre class="code"><span style="color: blue">select distinct </span><span style="color: gray">LEFT(</span>P<span style="color: gray">.</span>ProductNumber<span style="color: gray">, </span>6<span style="color: gray">) </span><span style="color: blue">as </span>ProductCodeWithoutColorAndSize<span style="color: gray">,
    </span>P<span style="color: gray">.</span>Color
<span style="color: blue">from </span>Production<span style="color: gray">.</span>Product P
<span style="color: blue">where </span>P<span style="color: gray">.</span>Color <span style="color: gray">is not null</span></pre>
<p><a href="http://11011.net/software/vspaste"></a>When looking at the product codes, I noticed that for the products which are available in several colors and sizes, the last four characters represent the color and size.&#160; Which means the first six characters define the product itself, without color or size.&#160; That’s why the query is using the Left function to create a product code of only the first six characters of the ProductNumber.&#160; Using the distinct keyword, we remove any duplicate records.</p>
<p>(Please note that I’m not 100% sure if this logic applies to all products but for this demo it’s fine.)</p>
<p>Here’s what the query retrieves:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="List of product colors per product" border="0" alt="List of product colors per product" src="http://blog.hoegaerden.be/wp-content/uploads/image255.png" width="264" height="321" /> </p>
<p>As you can see, for some products there’s more than one record.&#160; And that’s exactly what the <a title="BOL2008R2: LookupSet Function" href="http://msdn.microsoft.com/en-us/library/ee210576%28v=SQL.105%29.aspx" target="_blank">LookupSet function</a> was made for: it retrieves a set of data based on the key given to it.&#160; This is different from the Lookup, where for each key value it would fetch only one value.</p>
<p>Again I’ve added an additional row inside the Details group and used a placeholder with the following expression:</p>
<pre class="code">=Join(
    LookupSet(
        Left(Fields!ProductAlternateKey.Value, 6),
        Fields!ProductCodeWithoutColorAndSize.Value,
        Fields!Color.Value,
        <span style="color: #a31515">&quot;dsProductColors&quot;
    </span>),
    <span style="color: #a31515">&quot;, &quot;
</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>The LookupSet call itself looks very similar to the Lookup, with the same four parameters.&#160; I’ve used the Left function on the first parameter to apply the same logic to the ProductAlternateKey as we did with the ProductNumber.</p>
<p>However, there’s one important difference: the call of the Join function.&#160; This is needed because the LookupSet is returning a set, or better, a VariantArray, not just a single value.&#160; And an array cannot be visualized without first concatenating the values somehow.&#160; With the Join, we can concatenate the different values, using a comma as separator.</p>
<p>And here’s the resulting report:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Our report displaying the list of colors for each product" border="0" alt="Our report displaying the list of colors for each product" src="http://blog.hoegaerden.be/wp-content/uploads/image256.png" width="519" height="341" /> </p>
<p>With the first two lookup functions covered there’s one more to go.</p>
<h3>Just One More Lookup: The MultiLookup Function</h3>
<p>Guess what crazy request the business people have come up with this time?!&#160; The report should have a multi-value filter on region, and for each region selected, the top of the table should list the number of shops opened in the first year in those regions.&#160; For example, if the first shop in France was opened in 1970 and in that same year there were two other shops opened in France, the report should state “France: 3 shop(s) opened in 1970”.</p>
<p>Ow, and that list should be located right under the main header so deciding to use a textbox outside of the table is not a good idea <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Sounds like we can use the <a title="BOL2008R2: Multilookup Function" href="http://msdn.microsoft.com/en-us/library/ee210583%28v=SQL.105%29.aspx" target="_blank">MultiLookup</a> function for this request.&#160; But let’s first set up the filter.</p>
<p>I’ve created a dataset called dsRegions, using the following query on the data warehouse:</p>
<pre class="code"><span style="color: blue">select </span>DST<span style="color: gray">.</span>SalesTerritoryAlternateKey<span style="color: gray">,
    </span>DST<span style="color: gray">.</span>SalesTerritoryCountry <span style="color: gray">+ </span><span style="color: red">' - ' </span><span style="color: gray">+ </span>DST<span style="color: gray">.</span>SalesTerritoryRegion <span style="color: blue">as </span>CountryRegion
<span style="color: blue">from </span>DimSalesTerritory DST
<span style="color: blue">where </span>DST<span style="color: gray">.</span>SalesTerritoryAlternateKey <span style="color: gray">&gt; </span>0</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Then I’ve added a multi-value parameter called Regions with the Available Values coming from the dsRegions dataset.</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Regions parameter: the Available Values" border="0" alt="Regions parameter: the Available Values" src="http://blog.hoegaerden.be/wp-content/uploads/image257.png" width="585" height="482" /> </p>
<p>This parameter can now be used in our main dataset.&#160; Here’s the updated query:</p>
<p><a href="http://11011.net/software/vspaste"></a></p>
<pre class="code"><span style="color: blue">select </span>PROD<span style="color: gray">.</span>EnglishProductName<span style="color: gray">, </span>PROD<span style="color: gray">.</span>ProductAlternateKey<span style="color: gray">, </span>PROD<span style="color: gray">.</span>ListPrice<span style="color: gray">,
    </span>PSC<span style="color: gray">.</span>EnglishProductSubcategoryName<span style="color: gray">, </span>PC<span style="color: gray">.</span>EnglishProductCategoryName<span style="color: gray">,
    </span>S<span style="color: gray">.</span>OrderQuantity<span style="color: gray">, </span>S<span style="color: gray">.</span>SalesAmount
<span style="color: blue">from </span>FactInternetSales S
<span style="color: gray">inner join </span>DimProduct PROD <span style="color: blue">on </span>S<span style="color: gray">.</span>ProductKey <span style="color: gray">= </span>PROD<span style="color: gray">.</span>ProductKey
<span style="color: gray">inner join </span>DimProductSubcategory PSC
    <span style="color: blue">on </span>PROD<span style="color: gray">.</span>ProductSubcategoryKey <span style="color: gray">= </span>PSC<span style="color: gray">.</span>ProductSubcategoryKey
<span style="color: gray">inner join </span>DimProductCategory PC <span style="color: blue">on </span>PSC<span style="color: gray">.</span>ProductCategoryKey <span style="color: gray">= </span>PC<span style="color: gray">.</span>ProductCategoryKey
<span style="color: gray">inner join </span>DimSalesTerritory DST <span style="color: blue">on </span>S<span style="color: gray">.</span>SalesTerritoryKey <span style="color: gray">= </span>DST<span style="color: gray">.</span>SalesTerritoryKey
<span style="color: blue">where </span>DST<span style="color: gray">.</span>SalesTerritoryAlternateKey <span style="color: gray">in (</span>@Regions<span style="color: gray">)</span></pre>
<p><a href="http://11011.net/software/vspaste"></a>The only difference with the previous query are the two last lines: we add DimSalesTerritory to the joins and filter it on SalesTerritoryAlternateKey.</p>
<p>Don’t forget to set up the parameter.</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Setting up the parameter on dsInternetSales" border="0" alt="Setting up the parameter on dsInternetSales" src="http://blog.hoegaerden.be/wp-content/uploads/image258.png" width="600" height="234" /> </p>
<p>With the filter implemented, let’s get started on that extra lookup.&#160; </p>
<p>First we need to add the dataset containing the data that we need.&#160; I’ve created a dataset called dsShopsOpenedInFirstYear, using the following query on the relational database:</p>
<pre class="code"><span style="color: blue">with </span>ShopOpened <span style="color: blue">as
</span><span style="color: gray">(
    </span><span style="color: blue">select </span>T<span style="color: gray">.</span>TerritoryID<span style="color: gray">, </span>T<span style="color: gray">.</span>Name Territory<span style="color: gray">, </span>S<span style="color: gray">.</span>Name ShopName<span style="color: gray">,
        </span>S<span style="color: gray">.</span>[Demographics]<span style="color: gray">.</span>value<span style="color: gray">(</span><span style="color: red">'declare default element namespace &quot;http://schemas.microsoft.com/sqlserver/2004/07/adventure-works/StoreSurvey&quot;;
        (/StoreSurvey/YearOpened)[1]'</span><span style="color: gray">, </span><span style="color: red">'integer'</span><span style="color: gray">) </span><span style="color: blue">AS </span>[YearOpened]
    <span style="color: blue">from </span>Sales<span style="color: gray">.</span>Store S
    <span style="color: gray">inner join </span>Sales<span style="color: gray">.</span>SalesPerson SP <span style="color: blue">on </span>S<span style="color: gray">.</span>SalesPersonID <span style="color: gray">= </span>SP<span style="color: gray">.</span>BusinessEntityID
    <span style="color: gray">inner join </span>Sales<span style="color: gray">.</span>SalesTerritory T <span style="color: blue">on </span>SP<span style="color: gray">.</span>TerritoryID <span style="color: gray">= </span>T<span style="color: gray">.</span>TerritoryID
<span style="color: gray">),
</span>FirstShopOpened <span style="color: blue">as
</span><span style="color: gray">(
    </span><span style="color: blue">select </span><span style="color: magenta">MIN</span><span style="color: gray">(</span>YearOpened<span style="color: gray">) </span>YearOpened<span style="color: gray">, </span>TerritoryID
    <span style="color: blue">from </span>ShopOpened
    <span style="color: blue">group by </span>TerritoryID
<span style="color: gray">)
</span><span style="color: blue">select </span>SO<span style="color: gray">.</span>TerritoryID<span style="color: gray">,
    </span>SO<span style="color: gray">.</span>Territory <span style="color: gray">+ </span><span style="color: red">': ' </span><span style="color: gray">+ </span><span style="color: magenta">CAST</span><span style="color: gray">(</span><span style="color: magenta">COUNT</span><span style="color: gray">(*) </span><span style="color: blue">as varchar</span><span style="color: gray">(</span>100<span style="color: gray">)) +
    </span><span style="color: red">' shop(s) opened in ' </span><span style="color: gray">+ </span><span style="color: magenta">CAST</span><span style="color: gray">(</span>SO<span style="color: gray">.</span>YearOpened <span style="color: blue">as char</span><span style="color: gray">(</span>4<span style="color: gray">)) </span><span style="color: blue">as </span>ShopString
<span style="color: blue">from </span>FirstShopOpened FSO
<span style="color: gray">inner join </span>ShopOpened SO <span style="color: blue">on </span>SO<span style="color: gray">.</span>TerritoryID <span style="color: gray">= </span>FSO<span style="color: gray">.</span>TerritoryID
    <span style="color: gray">and </span>SO<span style="color: gray">.</span>YearOpened <span style="color: gray">= </span>FSO<span style="color: gray">.</span>YearOpened
<span style="color: blue">group by </span>SO<span style="color: gray">.</span>TerritoryID<span style="color: gray">, </span>SO<span style="color: gray">.</span>Territory<span style="color: gray">, </span>SO<span style="color: gray">.</span>YearOpened</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>This query uses a couple of <a title="BOL2008: Using Common Table Expressions" href="http://msdn.microsoft.com/en-us/library/ms190766.aspx" target="_blank">Common Table Expressions</a> to get to the result as we need it.&#160; The first CTE, ShopOpened, creates a list of all shops with their territory and the opening year.&#160; The second CTE, FirstShopOpened uses the ShopOpened CTE to retrieve the first opening year for each territory.</p>
<p>And finally the main query uses both CTEs to create the following result:</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Number of shops opened in first year per territory" border="0" alt="Number of shops opened in first year per territory" src="http://blog.hoegaerden.be/wp-content/uploads/image259.png" width="336" height="236" /> </p>
<p>For each territory we’ve constructed a string that shows how many shops were opened in the first year of that region, and in what year it happened.&#160; Coincidentally all regions had shops opened in 1970.</p>
<p>The TerritoryID corresponds with the SalesTerritoryAlternateKey, which is the value of our Regions parameter.</p>
<p>I’ve added an extra row under the top row in the table data region, and I’m using the following expression in that row:</p>
<pre class="code">=Join(
    MultiLookup(
        Parameters!Regions.Value,
        Fields!TerritoryID.Value,
        Fields!ShopString.Value,
        <span style="color: #a31515">&quot;dsShopsOpenedInFirstYear&quot;
    </span>),
    <span style="color: #a31515">&quot;&lt;br&gt;&quot;
</span>)</pre>
<p>The MultiLookup takes four parameters, just like the two previous lookup functions.&#160; They are all the same, except for the first one.&#160; It may not be very obvious in the example here, but the Parameters!Regions.Value is in fact not just a single value.&#160; It’s an array because we’ve set up the parameter as being multi-valued.</p>
<p>And that’s exactly what the MultiLookup function requires.&#160; Here’s the description for that first parameter, as stated in the Books Online:</p>
<blockquote>
<p>(<strong>VariantArray</strong>) An expression that is evaluated in the current scope and that specifies the set of names or keys to look up. For example, for a multivalue parameter, <code>=Parameters!IDs.value</code>.</p>
</blockquote>
<p>Just like the LookupSet function, MultiLookup returns a VariantArray, so we use the Join function to concatenate the values.</p>
<p>Interesting to note here is that I’m adding the break HTML tag as separator.&#160; I want the result of the expression to be treated as HTML, so that each value retrieved ends up at a new line in the textbox.&#160; To get this to work as expected, you need to tell the Placeholder that the resulting value should be treated as HTML:</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Using HTML in a Placeholder" border="0" alt="Using HTML in a Placeholder" src="http://blog.hoegaerden.be/wp-content/uploads/image260.png" width="592" height="479" /> </p>
<p>Everything is now set up to have another report Preview.&#160; The following screenshot shows the report with the data filtered on Canada, France and Australia:</p>
<p><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="The final report performing three different lookups" border="0" alt="The final report performing three different lookups" src="http://blog.hoegaerden.be/wp-content/uploads/image261.png" width="518" height="452" /> </p>
<p>Seems to be working fine, doesn’t it?</p>
<p>Okay, that’s it for now, have fun looking up that data!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="BOL2008R2: Lookup Function" href="http://msdn.microsoft.com/en-us/library/ee210575%28v=SQL.105%29.aspx" target="_blank">BOL2008R2: Lookup Function</a></p>
<p><a title="BOL2008R2: LookupSet Function" href="http://msdn.microsoft.com/en-us/library/ee210576%28v=SQL.105%29.aspx" target="_blank">BOL2008R2: LookupSet Function</a></p>
</p>
<p><a title="BOL2008R2: MultiLookup Function" href="http://msdn.microsoft.com/en-us/library/ee210583%28v=SQL.105%29.aspx" target="_blank">BOL2008R2: MultiLookup Function</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2010/05/16/looking-up-data-on-different-sources/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Importing Excel Data Using Integration Services</title>
		<link>http://blog.hoegaerden.be/2010/04/20/importing-excel-data-using-integration-services/</link>
		<comments>http://blog.hoegaerden.be/2010/04/20/importing-excel-data-using-integration-services/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 21:21:02 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Integration Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2010/04/20/importing-excel-data-using-integration-services/</guid>
		<description><![CDATA[In a previous article I’ve shown you how to import data from an Excel sheet using the OPENROWSET() function.&#160; And I concluded by stating that it’s not the best option when automating your data import.
Today I’ll repeat the Excel data import process by using SQL Server Integration Services, also known as SSIS.
I’ll be using SQL [...]]]></description>
			<content:encoded><![CDATA[<p>In a previous article I’ve shown you <a title="Retrieving Data From Excel" href="http://blog.hoegaerden.be/2010/03/29/retrieving-data-from-excel/" target="_blank">how to import data from an Excel sheet using the OPENROWSET() function</a>.&#160; And I concluded by stating that it’s not the best option when automating your data import.</p>
<p>Today I’ll repeat the Excel data import process by using SQL Server Integration Services, also known as SSIS.</p>
<p>I’ll be using SQL Server 2008 R2, but I’m quite sure that the process is very similar to the first release of 2008, and even to 2005.&#160; The Excel file that I will be importing is the one used in my previous article, and I’ll also refer to some parts of that article, so you may want to have a read over that one when something here isn’t clear.</p>
<p>Furthermore I’m using a Windows 7 64-bit machine, with <a title="2010 Office System Driver Beta: Data Connectivity Components" href="http://www.microsoft.com/downloads/details.aspx?FamilyID=C06B8369-60DD-4B64-A44B-84B371EDE16D&amp;amp;displaylang=ja&amp;displaylang=en" target="_blank">the ACE 14 driver</a> (beta) installed.&#160; To avoid any discussion about versions and for my own (future) reference, here’s the result of a SELECT @@VERSION:</p>
<blockquote><p>Microsoft SQL Server 2008 R2 (CTP) &#8211; 10.50.1352.12 (X64)&#160;&#160; Oct 30 2009 18:06:48&#160;&#160; Copyright (c) Microsoft Corporation&#160; Enterprise Evaluation Edition (64-bit) on Windows NT 6.1 &lt;X64&gt; (Build 7600: ) </p>
</blockquote>
<h2>Create SSIS Package To Import Excel Data</h2>
<p>Usually you will start by creating a new package in an Integration Services project, add an Excel source to a new Data Flow, throw in some Data Flow Transformations and end your flow with an OLE DB Destination connecting to your SQL Server.</p>
<p>But that’s not the approach that I’ll take in this article.&#160; I’ll make use of a shortcut (and meanwhile I’m showing you how well integrated some components really are).</p>
<p>First, I’m creating a new database called <em>ExcelImport</em>, using the Management Studio (aka SSMS).&#160; Once the database is created, right-click on it and choose Tasks &gt; Import Data.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Start the Import Data Wizard through Management Studio" border="0" alt="Start the Import Data Wizard through Management Studio" src="http://blog.hoegaerden.be/wp-content/uploads/image213.png" width="586" height="652" /> </p>
<p>This will open up the <a title="BOL 2008: Importing and Exporting Data by Using the SQL Server Import and Export Wizard" href="http://msdn.microsoft.com/en-us/library/ms141209.aspx" target="_blank">SQL Server Import And Export Data Wizard</a>.&#160; Like all good wizards, it starts with a <strong>Welcome</strong> screen containing an introductory text about its purpose – something about “create simple packages that import and export data between many popular data formats including databases, spreadsheets” – and so on.&#160; It also includes a checkbox that says “Do not show this starting page again”.&#160; That’s my favorite object on the page <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> &#160; Okay, I agree, the page is useful for people who have never seen the wizard before and who may have opened it up by accident, but that’s about as far as its use goes methinks.</p>
<p>So, do whatever you like with the checkbox and click Next.&#160; That opens up the <strong>Choose a Data Source</strong> screen.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Choose a Data Source" border="0" alt="SQL Server Import and Export Wizard - Choose a Data Source" src="http://blog.hoegaerden.be/wp-content/uploads/image214.png" width="566" height="579" /> </p>
<p>In that screen you have several options in the Data Source dropdown.&#160; The one we’re interested in is called <em>Microsoft Excel</em>.&#160; Once that option is selected, the controls further down the screen change into what is shown in the screenshot.&#160; Select your file and the right version, in my case I’ve got an Excel 2007 file.&#160; If your sheet contains a header row, activate the <em>First row has column names</em> checkbox.</p>
<p>Clicking Next will open up the <strong>Choose a Destination</strong> screen.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Choose a Destination" border="0" alt="SQL Server Import and Export Wizard - Choose a Destination" src="http://blog.hoegaerden.be/wp-content/uploads/image215.png" width="566" height="579" /> </p>
<p>In that screen, select <em>Microsoft OLE DB Provider for SQL Server</em> as Destination.&#160; Ensure that your SQL Server instance is the right one in the <em>Server Name</em> dropdown and the <em>Authentication</em> is filled out as expected.&#160; The correct database should be selected by default because we did a right-click on it to start the wizard.</p>
<p>Another Next click opens up the <strong>Specify Table Copy or Query</strong> window.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Specify Table Copy or Query" border="0" alt="SQL Server Import and Export Wizard - Specify Table Copy or Query" src="http://blog.hoegaerden.be/wp-content/uploads/image216.png" width="566" height="579" /> </p>
<p>Here we can choose between either retrieving the full table – all rows, all columns – or writing a query ourselves.&#160; I’ll go for the first option.</p>
<p>Click Next once more to open the <strong>Select</strong> <strong>Source Tables and Views</strong> screen.&#160; That name seems a bit weird in the context of an Excel import but I guess that’s not really important here.&#160; Just read it as “Select the sheet that you’d like to import”.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Select Source Table and Views" border="0" alt="SQL Server Import and Export Wizard - Select Source Table and Views" src="http://blog.hoegaerden.be/wp-content/uploads/image217.png" width="567" height="579" />&#160;</p>
<p>I’ll go for the ProductList$ Source.&#160; The sheet in my Excel file is called ProductList.&#160; Note that the Destination is editable – I’m changing the destination table to dbo.ProductList (with the dollar sign removed).</p>
<p>If you’d like to view your data right now you can hit the Preview button.&#160; It opens up a window such as this one:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Select Source Table and Views - Preview Data" border="0" alt="SQL Server Import and Export Wizard - Select Source Table and Views - Preview Data" src="http://blog.hoegaerden.be/wp-content/uploads/image218.png" width="528" height="338" />&#160; </p>
<p>That should look familiar.</p>
<p>A more interesting button is the one called <em>Edit Mappings</em>.&#160; Clicking that button opens a screen that lets you change the destination table’s schema.&#160; By default, all columns that seem to be numeric are mapped to a type of float and all the others are mapped to nvarchar with a length of 255.&#160; Depending on your situation you can either leave it as it is (in case you’re just loading a staging table and want to handle data conversions later on) or you should review each column (for instance when you’re erasing and loading the full table every night and this is the actual table being used by other processes).</p>
<p><strong>Note:</strong> whenever a column contains a blank cell, its type will be nvarchar(255), even when all other values are numeric.&#160; Also, if you don’t need Unicode support, don’t use nvarchar but change it to varchar instead.</p>
<p>Here’s the <strong>Column Mappings </strong>screen with some of the defaults changed:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The Column Mappings window" border="0" alt="The Column Mappings window" src="http://blog.hoegaerden.be/wp-content/uploads/image219.png" width="636" height="794" /> </p>
<p>Everything that I changed has been indicated using the yellow marker.&#160; I’ve changed some field types and lenghts, made one field non-nullable and adapted the destination name.</p>
<p>Clicking OK followed by Next brings us to the following screen, <strong>Review Data Type Mapping</strong>.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image220.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Review Data Type Mapping" border="0" alt="SQL Server Import and Export Wizard - Review Data Type Mapping" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb56.png" width="678" height="834" /></a> </p>
<p>This screen gives another overview of all the columns that we’re planning to import.&#160; Note that each column of which we’ve changed the type has gotten a nice yellow warning sign.&#160; This happens because a data conversion needs to occur, and there’s always something that can go wrong when converting data.&#160; The<em> On Error</em> and <em>On Truncation</em> columns show the action that should happen when such an event occurs.&#160; We’ll leave them all at <em>Use Global</em>.&#160; The Global settings are located at the bottom of the screen and are both set to <em>Fail</em>.&#160; That’s the best option at the moment (the only other one is <em>Ignore</em> but that means you won’t get any notification in case of an error or truncation problem).</p>
<p>After clicking Next we end up at the <strong>Save and Run Package</strong> window.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Save and Run Package" border="0" alt="SQL Server Import and Export Wizard - Save and Run Package" src="http://blog.hoegaerden.be/wp-content/uploads/image221.png" width="644" height="579" /> </p>
<p>I have activated the <em>Save SSIS Package</em> checkbox and chose the <em>Do not save sensitive data</em> option.&#160; By default it is saved in SQL Server, which is actually the MSDB.&#160; That’s good because we’re going to examine the contents of the package later on so we want to keep it.</p>
<p>The <em>Run immediately </em>checkbox was activated by default.&#160; This will execute the package in the last step of the wizard.</p>
<p>Another Next click and we’re on the <strong>Save SSIS Package </strong>screen.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Save SSIS Package" border="0" alt="SQL Server Import and Export Wizard - Save SSIS Package" src="http://blog.hoegaerden.be/wp-content/uploads/image222.png" width="566" height="579" /> </p>
<p>Here we can give our package a decent name, such as ExcelImport.&#160; You can also see the server on which I’m saving the package.</p>
<p>The final Next click brings us to the <strong>Complete the Wizard</strong> screen, woohoo!</p>
<p>&#160;<img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - Complete the Wizard" border="0" alt="SQL Server Import and Export Wizard - Complete the Wizard" src="http://blog.hoegaerden.be/wp-content/uploads/image223.png" width="566" height="579" /> </p>
<p>We can see a short overview of what we’ve configured in the previous steps.&#160; Click Finish to execute and save the package!</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="SQL Server Import and Export Wizard - The execution was successful" border="0" alt="SQL Server Import and Export Wizard - The execution was successful" src="http://blog.hoegaerden.be/wp-content/uploads/image224.png" width="566" height="579" /> </p>
<p>And we’ve successfully executed the package!</p>
<h2>Taking A Closer Look At The SSIS Package</h2>
<p>When connecting to the Integration Services server (through SSMS for instance), I now have a new package in the root of the MSDB folder.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The ExcelImport SSIS package, stored in MSDB" border="0" alt="The ExcelImport SSIS package, stored in MSDB" src="http://blog.hoegaerden.be/wp-content/uploads/image225.png" width="269" height="171" /> </p>
<p>It’s located there because I chose to save the package to SQL Server.</p>
<h3>Adding An Existing Package To An SSIS Project</h3>
<p>We’re now going to open it in the Business Intelligence Development Studio (aka BIDS).&#160; So, open the BIDS and create a new SSIS Project (or use an existing one, doesn’t really matter).</p>
<p>Once the project is open, right-click the SSIS Packages folder in the Solution Explorer and select <em>Add Existing Package</em>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Right-click SSIS Packages folder in Solution Explorer to Add Existing Package" border="0" alt="Right-click SSIS Packages folder in Solution Explorer to Add Existing Package" src="http://blog.hoegaerden.be/wp-content/uploads/image226.png" width="357" height="316" /> </p>
<p>That opens up the <em>Add Copy of Existing Package</em> window.</p>
<p><strong>Sidenote</strong>: do you see that <em>SSIS Import and Export Wizard</em> option in the previous screenshot?&#160; That’s right, the wizard that we’ve used extensively in the earlier part of this article can be launched from here as well.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Add Copy of Existing Package" border="0" alt="Add Copy of Existing Package" src="http://blog.hoegaerden.be/wp-content/uploads/image227.png" width="600" height="438" /> </p>
<p>Select <em>SSIS Package Store</em> as location of the package and enter the name of your server in the second dropdown.&#160; Once that is done you can click the button with the ellipsis and select your package under the MSDB node.</p>
<p>Clicking OK will add the package to your project in the Solution Explorer.&#160; Double-click it to open it up.</p>
<h3>The Control Flow</h3>
<p>In the Control Flow you can see two components: a SQL Task that contains a CREATE TABLE statement and a Data Flow.</p>
<p>Here’s what the CREATE TABLE statement looks like:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="CREATE TABLE statement in the Execute SQL Task" border="0" alt="CREATE TABLE statement in the Execute SQL Task" src="http://blog.hoegaerden.be/wp-content/uploads/image228.png" width="336" height="479" /> </p>
<p>As you can see, the table is created using the column names and types just like we configured them through the wizard.</p>
<p>Important to note here is that the Control Flow does not take anything else into account.&#160; For instance, what happens if we execute the package twice?&#160; It will fail because the table already exists!</p>
<p>In case you don’t believe me, just try it out!</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Execute SQL Statement failed" border="0" alt="Execute SQL Statement failed" src="http://blog.hoegaerden.be/wp-content/uploads/image229.png" width="167" height="149" />&#160;<img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="There is already an object named &#39;ProductList&#39; in the database." border="0" alt="There is already an object named &#39;ProductList&#39; in the database." src="http://blog.hoegaerden.be/wp-content/uploads/image230.png" width="861" height="144" />&#160;</p>
<h3>The Data Flow</h3>
<p>Opening up the Data Flow we see that it contains three components: an Excel source component that uses an Excel Connection Manager to connect to our now well-known Excel sheet, a Data Conversion Transformation to take care of the conversions that we requested and an OLE DB Destination that uses an OLE DB Connection Manager to connect to our SQL Server.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The Data Flow to transfer Excel data into SQL Server" border="0" alt="The Data Flow to transfer Excel data into SQL Server" src="http://blog.hoegaerden.be/wp-content/uploads/image232.png" width="165" height="227" /> </p>
<p>Important to note here is that whenever an issue occurs, such as a conversion problem, the flow will fail.</p>
<p>In production environments, certain events need to be taken into account.&#160; The purpose of this article was just to show you how you can use a wizard to generate an SSIS package for you.&#160; You can now use this package as the basis for a well-developed Excel Import template.</p>
<h2>Conclusion</h2>
<p>With this article I hope to have shown you how to use Integration Services to import Excel data, and also that the Management Studio knows how to use other SQL Server components, such as SSIS, quite well.</p>
<p>If you’re running into some issues while using the wizard, or you just like reading what I write, <a title="Importing Data Using The Wizard: Mixing The Wrong Ingredients" href="http://blog.hoegaerden.be/2010/05/03/importing-data-using-the-wizard-mixing-the-wrong-ingredients/">check out my follow-up article covering some common pitfalls</a>.</p>
<p>Need to go to sleep now, long drive tomorrow, PASS European Conference in Germany!&#160; I do hope that Adam Saxton will be there because I was planning to see his presentations all day long.&#160; I already read that one of the speakers – Brent Ozar – won’t be able to make it.&#160; Darned ash cloud…&#160; Next time someone starts talking to me about Azure I’ll run away screaming.</p>
<p>Just kidding <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="Microsoft Support: How to import data from Excel to SQL Server" href="http://support.microsoft.com/kb/321686" target="_blank">Microsoft Support: How to import data from Excel to SQL Server</a></p>
</p>
<p><a title="BOL 2008 - How to: Run the SQL Server Import and Export Wizard" href="http://msdn.microsoft.com/en-us/library/ms140052.aspx" target="_blank">How to: Run the SQL Server Import and Export Wizard</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2010/04/20/importing-excel-data-using-integration-services/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Your First OLAP Report</title>
		<link>http://blog.hoegaerden.be/2010/01/24/your-first-olap-report/</link>
		<comments>http://blog.hoegaerden.be/2010/01/24/your-first-olap-report/#comments</comments>
		<pubDate>Sun, 24 Jan 2010 13:28:32 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2010/01/24/your-first-olap-report/</guid>
		<description><![CDATA[Introduction
This article is aimed at report developers who are used to develop reports using relational databases and have gotten a first-time assignment to develop reports on OLAP cubes.
It demonstrates how to build a report using SQL Server Reporting Services 2008 with data coming from an OLAP cube running on SQL Server Analysis Services 2008.
The OLAP [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>This article is aimed at report developers who are used to develop reports using relational databases and have gotten a first-time assignment to develop reports on OLAP cubes.</p>
<p>It demonstrates how to build a report using SQL Server Reporting Services 2008 with data coming from an OLAP cube running on SQL Server Analysis Services 2008.</p>
<p>The OLAP database used in the article is called “Adventure Works DW 2008”, available for <a title="CodePlex - SQL Server 2008 SR4 sample databases" href="http://msftdbprodsamples.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=37109" target="_blank">download at CodePlex</a>.</p>
<p>If you’re fairly new to Reporting Services (aka SSRS) and you find that this article is going a bit too fast, I’d like to point you to my other article which explains <a title="Reporting On Data From Stored Procedures (part 1)" href="http://blog.hoegaerden.be/2009/11/10/reporting-on-data-from-stored-procedures-part-1/">how to build a report that’s retrieving data using regular stored procedures</a>.</p>
<h2>OLAP &lt;&gt; OLTP</h2>
<p>When people are talking about databases, what they are usually referring to are “regular” relational <strong>OLTP</strong> databases.&#160; OLTP stands for Online Transaction Processing.&#160; As the name implies, these types of databases are built to handle many simultaneous transactions (consisting of actions such as inserts, updates, deletes) in real-time.&#160; I’m sure you’re familiar with these types of database so I won’t go further into them.</p>
<p><strong>OLAP</strong> (Online Analytical Processing) on the other hand is a totally different story.&#160; OLAP cubes are built to answer multi-dimensional analytical queries as fast as possible.&#160; For that purpose, what you can find in such a database are <strong>measures</strong> (these are the numbers) stored in cubes, and <strong>dimensions</strong> which allow filtering the measures.&#160; This filtering is often referred to as slicing and dicing.&#160; Furthermore, OLAP cubes contain pre-aggregated data, again to be able to answer queries as fast as possible.</p>
<p>Let’s make this clear with an example.&#160; Imagine the following request: </p>
<blockquote><p>“Give me the sum of all sales of product X for period Y in country Z.”</p>
</blockquote>
<p>Three dimensions can be recognized in that request: “product X” is found in the <strong>Product</strong> dimension, “period Y” in the <strong>Date</strong> dimension and “country Z” in the <strong>Geography</strong> dimension.&#160; (I’ve used the actual dimension names as they are called in the Adventure Works OLAP database.)</p>
<p>Each dimension consists of <strong>attributes</strong> and <strong>attribute hierarchies</strong> and it’s those attributes that you’re actually referring to when building an <strong>MDX</strong> query.&#160; MDX stands for Multidimensional Expressions and that is the language used to query an OLAP database, just like you use SQL to query a relational database.</p>
<p>Looking at our example, what we need is for the Product attribute in the Product dimension to be equal to X.&#160; An attribute in a dimension can also be written as [Dimension].[Attribute], thus we also want [Date].[Date] to be equal to Y and [Geography].[Country] equal to Z.</p>
<p>As for the measure part, that’s what “the sum of all sales” is referring to.&#160; When looking at the measures available in the Adventure Works cube, one of the measures that would fulfill the request is the <strong>Reseller Sales Amount</strong> in the Reseller Sales measure group.&#160; The Analysis Services engine searches the cube and retrieves the aggregated number for [Measures].[Reseller Sales Amount] available at the intersection of [Product].[Product] X, [Date].[Date] Y and [Geography].[Country] Z.</p>
<p>OLAP cubes are usually, although not necessarily, build on top of a data warehouse.&#160; In SQL Server, a data warehouse is still a relational database, unlike an OLAP cube, but the table structure is different from an OLTP database.&#160; A data warehouse contains tables that represent dimensions and other tables that contain the facts.&#160; The facts are the numbers, so the measures that were mentioned earlier.&#160; This is called a dimensional model.&#160; Dimensional modeling was invented by Ralph Kimball, one of the pioneers in data warehousing.&#160; For completeness I’d like to mention that another data warehousing approach was described by Bill Inmon.&#160; I’ll leave it up to you to do some research on both approaches and decide for yourself which one you prefer, possibly even a mix of both.</p>
<p>As far as the “Adventure Works DW 2008” OLAP database is concerned, it’s built on top of the AdventureWorksDW2008 dimensional database.</p>
<p>Okay, I believe this theoretical explanation was sufficient for now, let’s start with the report!</p>
<h2>Your First Report</h2>
<h3>Business Requirements</h3>
<p>You’ve gotten the assignment to create a report that shows the reseller sales numbers by region.&#160; The highest level to be shown is Country, with drilldown through State/Province to City.</p>
<h3>Creating The Shared Data Source</h3>
<p>Just like when building reports on OLTP databases, we’re not going anywhere without a Data Source.&#160; I’m going to create a Shared Data Source called OLAP_AdventureWorks.rds:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Shared Data Source connecting to Adventure Works OLAP Database" border="0" alt="Shared Data Source connecting to Adventure Works OLAP Database" src="http://blog.hoegaerden.be/wp-content/uploads/image148.png" width="577" height="478" /> </p>
<p>The Type that we need is <strong>Microsoft SQL Server Analysis Services</strong>, which is the SQL Server service that’s running the OLAP databases.&#160; Furthermore I’ve selected the “Adventure Works DW 2008” database.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Connection Properties specifying the Adventure Works DW 2008 OLAP database" border="0" alt="Connection Properties specifying the Adventure Works DW 2008 OLAP database" src="http://blog.hoegaerden.be/wp-content/uploads/image149.png" width="308" height="410" /> </p>
<p>There’s no need to type the database name yourself.&#160; After you’ve provided sufficient credentials in the Credentials page, you can just select it from the dropdown in the Connection Properties screen.&#160; This screen is opened by clicking that Edit button on the Shared Data Source Properties window.</p>
<h3>Your First OLAP Dataset</h3>
<p>I’ve created a new report called FirstOLAPReport.rdl.&#160; In that report I’ve specified that I’ll be using the Shared Data Source created earlier.&#160; This source is known as srcAdventureWorksOLAP in my report.</p>
<p>Next step is to create the dataset.&#160; I’m calling it dsResellerSalesByRegion.&#160; As this is our first OLAP report, we’re not going to write the MDX ourselves but we will use the Query Designer which is opened by clicking the button that has the words Query Designer printed on them, how difficult can that be?!</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="How to open the MDX Query Designer" border="0" alt="How to open the MDX Query Designer" src="http://blog.hoegaerden.be/wp-content/uploads/image150.png" width="577" height="478" /> </p>
<p>The BIDS knows that it should open the MDX Query Designer because our data source is connecting to an Analysis Services server.&#160; All we need to do now is to drag the measures and dimension attributes that we require into the area marked with “Drag levels or measures here to add to the query.”.</p>
<p>Let’s start by dragging our measures into that area.&#160; We need two measures, both located in the Reseller Sales measure group.&#160; They are called Reseller Order Quantity and Reseller Sales Amount.&#160; Following screenshot shows the situation after the first measure has been added.&#160; The second measure was being dragged into it as well.&#160; When dragging items into the area, a vertical blue line appears to indicate where the item can be added.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="MDX Query Designer: dragging a measure into the query" border="0" alt="MDX Query Designer: dragging a measure into the query" src="http://blog.hoegaerden.be/wp-content/uploads/image151.png" width="627" height="706" /> </p>
<p>Next I’m going to drag the Geography hierarchy, located in the Geography dimension, into the design area.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="MDX Query Designer: dragging a hierarchy into the query" border="0" alt="MDX Query Designer: dragging a hierarchy into the query" src="http://blog.hoegaerden.be/wp-content/uploads/image152.png" width="620" height="647" /> </p>
<p>Now we’ve got all the data we need for our report.</p>
<p>As you have noticed, the Query Designer automatically executes the query each time it gets modified when you’re dragging an item into the design area.&#160; If you don’t want this behaviour, it can be switched off by clicking the <strong>Auto Execute</strong> button in the toolbar (indicated by a red 1 in the screenshot below).</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Query Designer toolbar" border="0" alt="Query Designer toolbar" src="http://blog.hoegaerden.be/wp-content/uploads/image153.png" width="487" height="61" /> </p>
<p>Another interesting button is the <strong>Design Mode</strong> button (indicated by a green 2).&#160; This one allows you to toggle between the graphical designer and the text editor.&#160; By clicking it you can see the actual MDX query that the designer has prepared for you.</p>
<p>As you can see, the query is nicely formatted using capitals for the keywords and so on.&#160; Well, no, actually it’s the worst editor around!&#160; No syntax coloring, no multi-line formatting, nothing.&#160; So if you are going to take a close look at the query, I recommend you to use the Management Studio.&#160; Connect to your Analysis Services server, locate your database and right-click it in the Object Explorer.&#160; Then choose New Query &gt; MDX and paste the query into that new window.&#160; You’ll still need to manually break it down into different lines but at least you get syntax coloring.&#160; Furthermore, if you’re going to make manual modifications to it, you’ve got some command completion and error indicators as well.</p>
<p>Please take into account that once you’ve made manual changes to your query, you cannot switch back to the graphical designer.&#160; Well, you can, but you will lose all manual modifications.&#160; Don’t worry about doing it accidentally though, a nice pop-up will warn you:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Warning message when switching back to design mode." border="0" alt="Warning message when switching back to design mode." src="http://blog.hoegaerden.be/wp-content/uploads/image154.png" width="611" height="131" /> </p>
<p>Something else that you’ll also notice is that the results displayed in the Query Designer and those displayed in the Management Studio are not exactly the same.&#160; That’s because both environments interpret the results differently.&#160; Remember, you’re not retrieving two-dimensional row/column data like with a SQL query.&#160; You’re retrieving multi-dimensional data!</p>
<p>If you take a closer look at the query that we’ve produced above, it’s similar to this:</p>
<pre class="code"><span style="color: blue">SELECT </span>something <span style="color: blue">ON COLUMNS</span>,
    something_else <span style="color: blue">ON ROWS
FROM </span>[Adventure Works]</pre>
<div>That query is selecting data on two axes: COLUMNS and ROWS.&#160; But in fact, MDX supports up to 128 axes.&#160; However, the client tools that we are using here are not able to visualize that kind of cellset (as the result set of an MDX query is also called).</div>
<div>&#160;</div>
<div>Okay, enough about our dataset.&#160; We’ve got the data, let’s put it on the report!</div>
<div>&#160;</div>
<h3>Displaying The Result Set</h3>
<p>As a reference, these are the fields available in our dataset:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Fields available in OLAP dataset" border="0" alt="Fields available in OLAP dataset" src="http://blog.hoegaerden.be/wp-content/uploads/image155.png" width="210" height="226" /> </p>
<p>Without going into too much detail – there’s no difference compared to reporting off a relational database &#8211; I’ve set up a table with three grouping levels on the rows.&#160; I’ve also added some makeup like background colors and font modifications.</p>
<p>As shown in following screenshot, the highest-level group is Country, followed by State_Province and City to conclude, just as specified in the requirements mentioned at the start of this chapter.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image156.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Table with three groupings defined" border="0" alt="Table with three groupings defined" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb40.png" width="676" height="208" /></a> </p>
<p>Rendering the report in preview gives us something like this:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image157.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report without any numeric formatting applied" border="0" alt="Report without any numeric formatting applied" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb41.png" width="677" height="382" /></a> </p>
<p>What is still missing at this point is decent formatting for those numbers!&#160; And here’s where we can take advantage of the fact that we’re retrieving data from an OLAP cube.&#160; A cube developer has the possibility to define the format for the measures in the cube itself.&#160; Doing that ensures that the same formatting is applied no matter what OLAP client tool is used.&#160; Any client that supports this way of formatting will show the numbers using the same format.</p>
<p>As you’ve seen in that last screenshot, there’s no formatting applied at all.&#160; Does this mean that there was no format defined in the cube?&#160; Let’s find out!</p>
<h4>A Little Walk Into The Analysis Project</h4>
<p>We are going to open up the Analysis Services project that contains the cube definition.&#160; If you don’t have any experience with SSAS, don’t worry!&#160; We will just have a look at a couple of properties and that’s it, plus I’ll explain each step as needed.&#160; In case you’ve forgotten where the sources are located, this is the default location: C:\Program Files\Microsoft SQL Server\100\Tools\Samples\AdventureWorks Analysis Services Project\.&#160; I’m opening the project located under the \enterprise subfolder by double-clicking the <em>Adventure Works.sln</em> file.</p>
<p>Once the project is loaded into the BIDS, locate and open the <em>Adventure Works.cube</em> in the Solution Explorer.&#160; You can find it in the <em>Cubes</em> folder of the <strong>Adventure Works DW</strong> project.</p>
<p>By default it will open the cube Design showing the first page called <strong>Cube Structure</strong>.&#160; At the top-left, we’ve got the Measures pane.&#160; The measures are shown in measure groups.&#160; Open the group called <em>Reseller Sales</em>.&#160; Now locate the measure called <em>Reseller Sales Amount</em> and select it.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Cube in Design with Reseller Sales Amount selected" border="0" alt="Cube in Design with Reseller Sales Amount selected" src="http://blog.hoegaerden.be/wp-content/uploads/image158.png" width="373" height="289" /> </p>
<p>Now that we’ve selected one of the measures that we are retrieving in our report, have a look at the Properties window.&#160; In case it’s not open yet you can right-click the measure and select Properties.&#160; The property that we’re interested in is called <strong>FormatString</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Properties of the Reseller Sales Amount measure showing Currency as format string" border="0" alt="Properties of the Reseller Sales Amount measure showing Currency as format string" src="http://blog.hoegaerden.be/wp-content/uploads/image168.png" width="435" height="252" /> </p>
<p>The cube developer has specified that this measure should be shown as being a <strong>Currency</strong>.</p>
<p>Now that you’re in the cube, have a look at the properties for our other measure, the <em>Reseller Order Quantity</em>.&#160; This one is being formatted as <strong>#,#</strong>.</p>
<h4>The FormattedValue Field Property</h4>
<p>So why are we not seeing those formats in our report?&#160; Because by default they are not applied in an SSRS report!&#160; When dragging fields from the <strong>Report Data</strong> window onto the design area, what the BIDS is retrieving is the <strong>Value</strong> property of the field.&#160; However, there’s also a property called <strong>FormattedValue</strong>.</p>
<p><em>(You may want to make a copy of your report before applying the following changes.)</em></p>
<p>Now, change the six table cells that are showing the numbers (so including the ones showing the totals) to retrieve the FormattedValue property instead of the Value property.&#160; The expression for the totals of the <strong>Reseller Sales Amount</strong> looks like this:</p>
<pre class="code">=Sum(Fields!Reseller_Sales_Amount.FormattedValue)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Once you’ve done that, have a look at the Preview:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Preview showing no numbers after retrieving the FormattedValue property" border="0" alt="Report Preview showing no numbers after retrieving the FormattedValue property" src="http://blog.hoegaerden.be/wp-content/uploads/image169.png" width="578" height="398" /> </p>
<p>That doesn’t look right, does it?&#160; We’ve lost our numbers!</p>
<p>Now hit the Refresh button: <img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Refresh button in Report Preview" border="0" alt="Refresh button in Report Preview" src="http://blog.hoegaerden.be/wp-content/uploads/image172.png" width="21" height="27" /> </p>
</p>
<p>This time we’ve got some numbers:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Preview showing formatted numbers, and errors!" border="0" alt="Report Preview showing formatted numbers, and errors!" src="http://blog.hoegaerden.be/wp-content/uploads/image170.png" width="571" height="399" /> </p>
<p>But we’ve also got some errors for free!&#160; Looking at the Output window we get some extra details on the reason for the error.&#160; Here’s one of them:</p>
<blockquote>
<p>[rsAggregateOfNonNumericData] The Value expression for the textrun ‘Reseller_Order_Quantity1.Paragraphs[0].TextRuns[0]’ uses a numeric aggregate function on data that is not numeric.&#160; Numeric aggregate functions (Sum, Avg, StDev, Var, StDevP, and VarP) can only aggregate numeric data.</p>
</blockquote>
<p>In short, what it says is that our data is not numeric.&#160; And this poses an issue when it tries to apply the SUM() aggregate function.&#160; Right, as our data now contains formatting, it became a string instead of a number, and strings can’t be added together using SUM().</p>
<p>So that’s not a good way to apply the formatting, not in this case anyway.&#160; Luckily there’s another method to do that.</p>
<p>But first, undo those last changes and replace the FormattedValue with the Value property.</p>
<p><em>(Or switch back to the original report if you took a copy earlier.)</em></p>
<h4>The Cell Properties</h4>
<p>What exactly is our MDX query doing?&#160; I’m taking a closer look at it by taking it from the Dataset Properties window and pasting it into a MDX query window in the Management Studio:</p>
<pre class="code"><span style="color: blue">SELECT
NON EMPTY </span>{ [Measures].[Reseller Sales Amount], [Measures].[Reseller Order Quantity] }
<span style="color: blue">ON COLUMNS</span>,
<span style="color: blue">NON EMPTY </span>{ ([Geography].[Geography].[Postal Code].<span style="color: maroon">ALLMEMBERS </span>) }
<span style="color: blue">DIMENSION PROPERTIES MEMBER_CAPTION</span>, <span style="color: blue">MEMBER_UNIQUE_NAME
ON ROWS
FROM </span>[Adventure Works]
<span style="color: blue">CELL PROPERTIES VALUE</span>, <span style="color: blue">BACK_COLOR</span>, <span style="color: blue">FORE_COLOR</span>, <span style="color: blue">FORMATTED_VALUE</span>,
<span style="color: blue">FORMAT_STRING</span>, <span style="color: blue">FONT_NAME</span>, <span style="color: blue">FONT_SIZE</span>, <span style="color: blue">FONT_FLAGS</span></pre>
<p>Besides retrieving the requested measures and dimension attributes, it’s retrieving several <a title="BOL 2008: Using Cell Properties (MDX)" href="http://msdn.microsoft.com/en-us/library/ms145573.aspx">Cell Properties</a>, including FORMATTED_VALUE and FORMAT_STRING.&#160; I believe that the first one rings a bell by now.&#160; What we’re going to do is to retrieve the second one and apply it as Format property for our numeric table cells.</p>
<p>In the report’s Design, select one of the table cells containing a number.&#160; In the Properties window, one of the properties is called Format.&#160; Click to select it, then in the dropdown choose Expression….&#160; For each of the six numeric cells, create an expression similar to the following:</p>
<pre class="code">=Fields!Reseller_Order_Quantity(<span style="color: #a31515">&quot;FORMAT_STRING&quot;</span>)</pre>
<p>The example above tells the BIDS to retrieve the FORMAT_STRING cell property from the Reseller_Order_Quantity field.</p>
<p><strong>Tip:</strong> you don’t need to open up the Expression builder for each of the six cells.&#160; You can just copy/paste the string from the Format field.&#160; Just ensure that you’re retrieving the format from the same field as the one that the cell is displaying.</p>
<p>Now let’s have a look at the Preview again:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Format is working for the quantity amounts but not for Currency!" border="0" alt="Format is working for the quantity amounts but not for Currency!" src="http://blog.hoegaerden.be/wp-content/uploads/image171.png" width="577" height="400" /> </p>
<p>Hmm,&#160; the quantities are fine now, but the currencies are not!&#160; So, let’s try out yet another method for those cells.</p>
<p>For the three cells containing a currency measure, remove the Format property – it’s not working anyway!</p>
<p>Next, change the expression that’s retrieving the Value property to something similar as this one:</p>
<pre class="code">=Format(Sum(Fields!Reseller_Sales_Amount.Value),
    Fields!Reseller_Sales_Amount(<span style="color: #a31515">&quot;FORMAT_STRING&quot;</span>))</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>This expression applies the value of the FORMAT_STRING property using the Format() function.&#160; In this particular case it’s the expression used to produce the Reseller Sales Amount total.</p>
<p>Having modified all three currency cells, here’s another Preview look:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image164.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Both Currency and regular numeric cells are showing formatted values!" border="0" alt="Both Currency and regular numeric cells are showing formatted values!" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb46.png" width="677" height="382" /></a> </p>
<p>That certainly looks better doesn’t it?!</p>
<p>Okay, to conclude, let’s activate drilldown by setting the subgroup levels to a collapsed state by default.</p>
<p>I will not go into full detail on this.&#160; To start, make sure that the cells that are going to contain the +/- toggle have gotten a decent name, such as txtCountry for the cell that shows the Country name.&#160; Then edit the properties of the subgroups by setting <strong>Visibility</strong> to <strong>Hide</strong>.&#160; Also, activate the <strong>Display can be toggled by this report item</strong> checkbox and select the textbox showing the label one level higher.&#160; Shown below is how to configure the group on State_Province.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image165.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Group Properties showing how to activate drilldown" border="0" alt="Group Properties showing how to activate drilldown" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb47.png" width="670" height="508" /></a> </p>
<p>&#160;</p>
<p>Let’s have another look at the report Preview:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image166.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Fully working drilldown report" border="0" alt="Fully working drilldown report" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb48.png" width="677" height="244" /></a> </p>
<p>By default all nodes were collapsed.&#160; I’ve expanded a couple of them just to show that it’s all working.</p>
<h4>The InitialToggleState Property</h4>
<p>Okay, I will not let you go just yet.&#160; To really conclude I’ll let you in on a little feature related to the drilldown.&#160; Open up the group properties for the State_Province group and set the initial visibility to <strong>Show</strong> (leave the “Display can be toggled by this report item” checked!).&#160; Then checkout Preview:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image167.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Visibility toggle is broken!" border="0" alt="Visibility toggle is broken!" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb49.png" width="677" height="167" /></a> </p>
<p>Wow, that’s weird, the country level is expanded and yet there’s a plus icon in front of the country’s name.&#160; Clicking it will collapse the states and change the icon to minus.&#160; If that isn’t mixed up then I don’t know what is!</p>
<p>Well, the solution to this problem is simple.&#160; Select the textbox showing the country name and locate the <strong>InitialToggleState</strong> property.&#160; By default this is set to <em>False</em>, which means collapsed or in other words, False shows the plus icon.&#160; Change it to <em>True</em> and now your initial state icon will be a minus! </p>
<h2>Conclusion</h2>
<p>With this article I believe to have shown you how to get started with reporting off an OLAP cube while throwing in a couple of tips in the process.</p>
<p>Have a look at another article that I wrote earlier, it explains an issue which you may run into when taking OLAP reporting a step further: <a title="SSRS and MDX: Detecting Missing Fields" href="http://blog.hoegaerden.be/2009/07/06/ssrs-and-mdx-detecting-missing-fields/">SSRS and MDX: Detecting Missing Fields</a></p>
<p>Happy Reporting!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="The Basic MDX Query (MDX)" href="http://msdn.microsoft.com/en-us/library/ms144785.aspx" target="_blank">BOL 2008: The Basic MDX Query</a></p>
<p><a href="http://msdn.microsoft.com/en-us/library/ms145573.aspx">BOL 2008: Using Cell Properties (MDX)</a></p>
<p><a title="Retrieving Cell Properties" href="http://www.artisconsulting.com/blogs/greggalloway/Lists/Posts/Post.aspx?ID=10" target="_blank">MDX: Retrieving Cell Properties</a> by Greg Galloway</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2010/01/24/your-first-olap-report/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Reporting On Data From Stored Procedures (part 2)</title>
		<link>http://blog.hoegaerden.be/2009/11/21/reporting-on-data-from-stored-procedures-part-2/</link>
		<comments>http://blog.hoegaerden.be/2009/11/21/reporting-on-data-from-stored-procedures-part-2/#comments</comments>
		<pubDate>Sat, 21 Nov 2009 20:59:14 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2009/11/21/reporting-on-data-from-stored-procedures-part-2/</guid>
		<description><![CDATA[Introduction
In a previous article I announced that I would write a sequel covering how to pass multiple-value parameters from a SQL Server Reporting Services report to a stored procedure.&#160; So that’s what I will be writing about in this article.
As usual, I will be using the AdventureWorks2008 sample database (running on SQL Server 2008 SP1), [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>In a <a title="Reporting On Data From Stored Procedures (part 1)" href="http://blog.hoegaerden.be/2009/11/10/reporting-on-data-from-stored-procedures-part-1/" target="_blank">previous article</a> I announced that I would write a sequel covering how to pass multiple-value parameters from a SQL Server Reporting Services report to a stored procedure.&#160; So that’s what I will be writing about in this article.</p>
<p>As usual, I will be using the AdventureWorks2008 sample database (running on SQL Server 2008 SP1), downloadable from <a title="SQL Server sample databases at CodePlex" href="http://www.codeplex.com/MSFTDBProdSamples" target="_blank">CodePlex</a>.</p>
<p>The examples in this article, Part 2, are building further on the result achieved when following the steps described in <a title="Reporting On Data From Stored Procedures (part 1)" href="http://blog.hoegaerden.be/2009/11/10/reporting-on-data-from-stored-procedures-part-1/" target="_blank">Part 1</a>, so please refer to the previous article if needed.</p>
<h2>Passing Multi-Value Parameter To Stored Procedure</h2>
<p>As we’ve already seen in Part 1, parameters can be passed from a Reporting Services report to a stored procedure.&#160; The parameter that was used was just a simple, single-valued parameter.&#160; However, a report parameter can be defined as being multi-value.&#160; Let’s set one up!</p>
<p>Our report currently shows a list of employees who were hired after the selected hire date.&#160; One of the columns being shown is the department in which they’re active.&#160; We will modify the report so that it’s possible to filter the data on department – only the selected departments are to be retrieved from the database.</p>
<h3>Creating A Multi-Value Report Parameter</h3>
<p>The first step is to create a new report parameter, so right-click the Parameters node in the Report Data pane and select <strong>Add Parameter…</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Data pane - Add Parameter" border="0" alt="Report Data pane - Add Parameter" src="http://blog.hoegaerden.be/wp-content/uploads/image121.png" width="257" height="151" /> </p>
<p>I’m calling my parameter Department, and I want it to be of type Integer.&#160; In case you’re wondering why Integer, it will become clear very soon.&#160; I have also checked the <strong>Allow multiple values</strong> checkbox:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Parameter Properties - setting up multi-value param" border="0" alt="Report Parameter Properties - setting up multi-value param" src="http://blog.hoegaerden.be/wp-content/uploads/image122.png" width="577" height="478" /> </p>
<p>We want to make the parameter user-friendly so that the user sees a list of departments and can just select those that he needs.&#160; That means the parameter needs to be populated with that list of departments.&#160; To be able to do that, we first need to create a new dataset that retrieves the list of departments.</p>
<p>So for now, close the Report Parameter Properties screen and use the following query to create a dataset called dsDepartmentList:</p>
<pre class="code"><span style="color: blue">select </span>D<span style="color: gray">.</span>DepartmentID<span style="color: gray">, </span>D<span style="color: gray">.</span>Name <span style="color: blue">as </span>DepartmentName
<span style="color: blue">from </span>HumanResources<span style="color: gray">.</span>Department D
<span style="color: blue">order by </span>D<span style="color: gray">.</span>Name <span style="color: blue">asc</span></pre>
<div>&#160;</div>
<p>This is what our query returns:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Result of DepartmentList query - a list of departments" border="0" alt="Result of DepartmentList query - a list of departments" src="http://blog.hoegaerden.be/wp-content/uploads/image123.png" width="272" height="351" /> </p>
<p>Once the dataset is created, open up the properties of the Department Report Parameter created just before and select the <strong>Available Values</strong> page.</p>
<p>On that page, select the <strong>Get values from a query</strong> radio button, choose dsDepartmentList in the <strong>Dataset</strong> dropdown, select DepartmentID as <strong>Value field</strong> and DepartmentName as <strong>Label field</strong>.&#160; The Label field is what the user sees while the Value field is what Reporting Services will use as value.&#160; After all, we want to pass the IDs of the selected departments to our stored procedure, not the department names.&#160; And we want the user to see the department names, not their ID.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Parameter Properties - Available Values" border="0" alt="Report Parameter Properties - Available Values" src="http://blog.hoegaerden.be/wp-content/uploads/image124.png" width="577" height="478" /> </p>
<p>By default, no values are selected.&#160; To make it a bit more user-friendly, let’s select all departments by default when the report first loads.&#160; This is done on the Default Values page.</p>
<p>Select the <strong>Get values from a query</strong> radio button, dsDepartmentList as <strong>Dataset</strong> and DepartmentID as <strong>Value field</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Parameter Properties - Default Values" border="0" alt="Report Parameter Properties - Default Values" src="http://blog.hoegaerden.be/wp-content/uploads/image125.png" width="577" height="478" /> </p>
<p>That’s it, the multi-value report parameter is created!&#160; Of course, at this moment it doesn’t have any effect on the report’s content yet (switch to Preview if you don’t believe me and have a look).&#160; We’ll get to that next.</p>
<h3>Discover What Is Being Passed To The Stored Procedure</h3>
<p>To be able to handle the values passed into our stored procedure, let’s first find out what exactly our report is passing into it.&#160; We’ll do this by temporarily creating a new stored proc that will just accept the parameter values and return them.</p>
<p>This is what our test SP looks like:</p>
<pre class="code"><span style="color: blue">CREATE PROCEDURE </span>MultiValueParam
    @MyParam <span style="color: blue">varchar</span><span style="color: gray">(</span>1000<span style="color: gray">)
</span><span style="color: blue">AS
BEGIN
    SELECT </span>@MyParam <span style="color: blue">as </span>TheParameterReturned<span style="color: gray">;
</span><span style="color: blue">END</span></pre>
<div>&#160;</div>
<p>It accepts one parameter and returns it in a field called TheParameterReturned.</p>
<p>Set up a new dataset that calls this SP, called dsMultiValueParamTest.&#160; I’m sure you know how to do this by now <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>When creating the dataset, on the Parameters page, select the new parameter [@Department] that we created earlier:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Dataset Properties - Parameters" border="0" alt="Dataset Properties - Parameters" src="http://blog.hoegaerden.be/wp-content/uploads/image126.png" width="577" height="478" /> </p>
<p>To see what the field contains, drag it from the Report Data pane onto the report canvas, above the table that was created in Part 1.&#160; Enlarge the textbox a bit and activate the Preview tab.&#160; Select a hire date (doesn’t matter which one) and click the View Report button.&#160; As we’ve set up the report to select all departments by default, we don’t need to select them manually.&#160; But of course if you want you can have a look in the Departments dropdown to check if they are actually selected.&#160; This is the result after clicking the View Report button:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Content Of Multi-Value Parameter" border="0" alt="Content Of Multi-Value Parameter" src="http://blog.hoegaerden.be/wp-content/uploads/image127.png" width="525" height="156" /> </p>
<p>If you compare that list of numbers with the result that our dsDepartmentList query returns, you’ll see that these are the values from the DepartmentID field in exactly the same order as in the query’s result.&#160; And separated by commas.&#160; So in other words: it’s a comma-separated string of selected values.</p>
<h3>Wrong Way To Implement The Parameter</h3>
<p>Now that we know what exactly the multi-value parameter passes to a stored procedure, let’s modify our main procedure by adding the extra parameter to it.</p>
<p>Here’s the modified procedure:</p>
<pre class="code"><span style="color: blue">ALTER PROCEDURE </span>GetEmployeeData
    @HireDate <span style="color: blue">date</span><span style="color: gray">,
    </span>@DepartmentList <span style="color: blue">varchar</span><span style="color: gray">(</span>1000<span style="color: gray">)
</span><span style="color: blue">AS
BEGIN
    SELECT </span>E<span style="color: gray">.</span>NationalIDNumber<span style="color: gray">, </span>E<span style="color: gray">.</span>JobTitle<span style="color: gray">, </span>E<span style="color: gray">.</span>BirthDate<span style="color: gray">, </span>E<span style="color: gray">.</span>MaritalStatus<span style="color: gray">, </span>E<span style="color: gray">.</span>Gender<span style="color: gray">,
        </span>E<span style="color: gray">.</span>HireDate<span style="color: gray">, </span>E<span style="color: gray">.</span>SalariedFlag<span style="color: gray">, </span>E<span style="color: gray">.</span>VacationHours<span style="color: gray">, </span>E<span style="color: gray">.</span>SickLeaveHours<span style="color: gray">,
        </span>D<span style="color: gray">.</span>GroupName <span style="color: blue">as </span>DepartmentGroupName<span style="color: gray">, </span>D<span style="color: gray">.</span>Name <span style="color: blue">as </span>DepartmentName<span style="color: gray">,
        </span>P<span style="color: gray">.</span>FirstName<span style="color: gray">, </span>P<span style="color: gray">.</span>MiddleName<span style="color: gray">, </span>P<span style="color: gray">.</span>LastName
    <span style="color: blue">FROM </span>HumanResources<span style="color: gray">.</span>Employee E
    <span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>EmployeeDepartmentHistory EDH
        <span style="color: blue">ON </span>EDH<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
        <span style="color: gray">AND </span>EDH<span style="color: gray">.</span>EndDate <span style="color: gray">IS NULL </span><span style="color: green">-- current active department does not have EndDate filled in
    </span><span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>Department D
        <span style="color: blue">ON </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">= </span>EDH<span style="color: gray">.</span>DepartmentID
    <span style="color: gray">INNER JOIN </span>Person<span style="color: gray">.</span>Person P
        <span style="color: blue">ON </span>P<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
    <span style="color: blue">WHERE </span>E<span style="color: gray">.</span>HireDate <span style="color: gray">&gt; </span>@HireDate
        <span style="color: gray">AND </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">IN (</span>@DepartmentList<span style="color: gray">);
</span><span style="color: blue">END</span></pre>
<div>&#160;</div>
<p>Since our parameter is a comma-separated list of our values, I’ve used the <a title="BOL 2008: IN (Transact-SQL)" href="http://msdn.microsoft.com/en-us/library/ms177682.aspx" target="_blank">IN operator</a> to filter on only the selected values.</p>
<p>Next we need to add the extra parameter to the dsEmployeeData dataset.&#160; Double-click it in the Report Data pane to get its properties and click the Refresh Fields button to have it add the new parameter to the list.&#160; Then switch to the Parameters page and select the [@DepartmentList] parameter as Parameter Value for the newly-added @DepartmentList parameter.</p>
<p>Close the properties popup and run the report by activating the Preview tab.</p>
<p>Oh no, an error!&#160; More precisely this one (I will only mention the last line):</p>
<blockquote>
<p>Conversion failed when converting the varchar value ‘12,1,16,14,10,9,11,4,7,8,5,13,6,3,15,2’ to data type smallint.</p>
</blockquote>
<p>This error comes from our stored procedure.&#160; It complains that it cannot convert the list of values from a string to a smallint.&#160; Weird isn’t it?&#160; Well, maybe not.&#160; Let’s have a look at what’s going on.</p>
<p>The following query would work perfectly:</p>
<pre class="code"><span style="color: blue">SELECT </span>E<span style="color: gray">.</span>NationalIDNumber<span style="color: gray">, </span>E<span style="color: gray">.</span>JobTitle<span style="color: gray">, </span>E<span style="color: gray">.</span>BirthDate<span style="color: gray">, </span>E<span style="color: gray">.</span>MaritalStatus<span style="color: gray">, </span>E<span style="color: gray">.</span>Gender<span style="color: gray">,
    </span>E<span style="color: gray">.</span>HireDate<span style="color: gray">, </span>E<span style="color: gray">.</span>SalariedFlag<span style="color: gray">, </span>E<span style="color: gray">.</span>VacationHours<span style="color: gray">, </span>E<span style="color: gray">.</span>SickLeaveHours<span style="color: gray">,
    </span>D<span style="color: gray">.</span>GroupName <span style="color: blue">as </span>DepartmentGroupName<span style="color: gray">, </span>D<span style="color: gray">.</span>Name <span style="color: blue">as </span>DepartmentName<span style="color: gray">,
    </span>P<span style="color: gray">.</span>FirstName<span style="color: gray">, </span>P<span style="color: gray">.</span>MiddleName<span style="color: gray">, </span>P<span style="color: gray">.</span>LastName
<span style="color: blue">FROM </span>HumanResources<span style="color: gray">.</span>Employee E
<span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>EmployeeDepartmentHistory EDH
    <span style="color: blue">ON </span>EDH<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
    <span style="color: gray">AND </span>EDH<span style="color: gray">.</span>EndDate <span style="color: gray">IS NULL </span><span style="color: green">-- current active department does not have EndDate filled in
</span><span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>Department D
    <span style="color: blue">ON </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">= </span>EDH<span style="color: gray">.</span>DepartmentID
<span style="color: gray">INNER JOIN </span>Person<span style="color: gray">.</span>Person P
    <span style="color: blue">ON </span>P<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
<span style="color: blue">WHERE </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">IN (</span>12<span style="color: gray">,</span>1<span style="color: gray">,</span>16<span style="color: gray">,</span>14<span style="color: gray">,</span>10<span style="color: gray">,</span>9<span style="color: gray">,</span>11<span style="color: gray">,</span>4<span style="color: gray">,</span>7<span style="color: gray">,</span>8<span style="color: gray">,</span>5<span style="color: gray">,</span>13<span style="color: gray">,</span>6<span style="color: gray">,</span>3<span style="color: gray">,</span>15<span style="color: gray">,</span>2<span style="color: gray">); </span></pre>
<div>&#160;</div>
<p>But that is not what is being executed by our SP!&#160; In the query above, we are passing a list of numbers to the IN operator.&#160; But our SP accepts a varchar, a string.&#160; Sure, the report parameter passes a list of numbers, but they are stored in a string!&#160; An equivalent query for what our SP actually executes is the following:</p>
<pre class="code"><span style="color: blue">SELECT </span>E<span style="color: gray">.</span>NationalIDNumber<span style="color: gray">, </span>E<span style="color: gray">.</span>JobTitle<span style="color: gray">, </span>E<span style="color: gray">.</span>BirthDate<span style="color: gray">, </span>E<span style="color: gray">.</span>MaritalStatus<span style="color: gray">, </span>E<span style="color: gray">.</span>Gender<span style="color: gray">,
    </span>E<span style="color: gray">.</span>HireDate<span style="color: gray">, </span>E<span style="color: gray">.</span>SalariedFlag<span style="color: gray">, </span>E<span style="color: gray">.</span>VacationHours<span style="color: gray">, </span>E<span style="color: gray">.</span>SickLeaveHours<span style="color: gray">,
    </span>D<span style="color: gray">.</span>GroupName <span style="color: blue">as </span>DepartmentGroupName<span style="color: gray">, </span>D<span style="color: gray">.</span>Name <span style="color: blue">as </span>DepartmentName<span style="color: gray">,
    </span>P<span style="color: gray">.</span>FirstName<span style="color: gray">, </span>P<span style="color: gray">.</span>MiddleName<span style="color: gray">, </span>P<span style="color: gray">.</span>LastName
<span style="color: blue">FROM </span>HumanResources<span style="color: gray">.</span>Employee E
<span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>EmployeeDepartmentHistory EDH
    <span style="color: blue">ON </span>EDH<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
    <span style="color: gray">AND </span>EDH<span style="color: gray">.</span>EndDate <span style="color: gray">IS NULL </span><span style="color: green">-- current active department does not have EndDate filled in
</span><span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>Department D
    <span style="color: blue">ON </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">= </span>EDH<span style="color: gray">.</span>DepartmentID
<span style="color: gray">INNER JOIN </span>Person<span style="color: gray">.</span>Person P
    <span style="color: blue">ON </span>P<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
<span style="color: blue">WHERE </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">IN (</span><span style="color: red">'12,1,16,14,10,9,11,4,7,8,5,13,6,3,15,2'</span><span style="color: gray">); </span></pre>
<div>&#160;</div>
<p>When executing that in the Management Studio, it will throw this error:</p>
<blockquote>
<p>Msg 245, Level 16, State 1, Line 1<br />
    <br />Conversion failed when converting the varchar value &#8216;12,1,16,14,10,9,11,4,7,8,5,13,6,3,15,2&#8242; to data type smallint.</p>
</blockquote>
<p>Doesn’t that look familiar?!</p>
<p>The reason for this error is the following.&#160; The DepartmentID field is of type smallint.&#160; Therefore SQL Server tries to convert the list of values to smallint.&#160; In the first SELECT statement, each value gets converted to smallint and all works fine.&#160; In the second SELECT, SQL Server sees just one value, a varchar(1000), and tries to convert that to a smallint.&#160; It fails because the value that the string contains is not convertible to smallint.&#160; If the string would contain only one value, it would actually work.</p>
<p>You can try it out by replacing the last line with this:</p>
<pre class="code"><span style="color: blue">WHERE </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">IN (</span><span style="color: red">'12'</span><span style="color: gray">); </span></pre>
<div>&#160;</div>
<h3>Right Way To Implement The Parameter</h3>
<p>We’ve seen that our first implementation of using the IN operator is not a good idea.&#160; So we need to find another way to get this stored procedure working.</p>
<p><strong>Note:</strong> it would actually be possible to use the previous method in combination with dynamic SQL but I’m not going to apply that technique here.&#160; In case you are interested in that method, just construct a long string that contains the whole query as it is in the working SELECT statement above.&#160; For more info on dynamic SQL I’d like to point you to this excellent article by SQL Server MVP Erland Sommarskog: <a title="The Curse and Blessings of Dynamic SQL" href="http://www.sommarskog.se/dynamic_sql.html" target="_blank">The Curse and Blessings of Dynamic SQL</a>.</p>
<p>The IN operator can take a subquery.&#160; So now we need to find a way to “select” the values out of our comma-separated string of values.&#160; I am not going to re-invent the wheel and use a function that’s mentioned in another great article by Erland Sommarskog.&#160; The article is called <a title="Arrays and Lists in SQL Server 2005" href="http://www.sommarskog.se/arrays-in-sql-2005.html" target="_blank">Arrays and Lists in SQL Server 2005</a> but is also applicable to 2008 and mentions a function called iter$simple_intlist_to_tbl.</p>
<p>For this article’s readability purposes I’ve renamed the function to list_to_tbl.&#160; Here’s the code to create it:</p>
<pre class="code"><span style="color: green">-- from http://www.sommarskog.se/arrays-in-sql-2005.html
-- original name: iter$simple_intlist_to_tbl
</span><span style="color: blue">CREATE FUNCTION </span>list_to_tbl <span style="color: gray">(</span>@list <span style="color: blue">nvarchar</span><span style="color: gray">(</span><span style="color: magenta">MAX</span><span style="color: gray">))
   </span><span style="color: blue">RETURNS </span>@tbl <span style="color: blue">TABLE </span><span style="color: gray">(</span>number <span style="color: blue">int </span><span style="color: gray">NOT NULL) </span><span style="color: blue">AS
BEGIN
   DECLARE </span>@pos        <span style="color: blue">int</span><span style="color: gray">,
           </span>@nextpos    <span style="color: blue">int</span><span style="color: gray">,
           </span>@valuelen   <span style="color: blue">int 

   SELECT </span>@pos <span style="color: gray">= </span>0<span style="color: gray">, </span>@nextpos <span style="color: gray">= </span>1 

   <span style="color: blue">WHILE </span>@nextpos <span style="color: gray">&gt; </span>0
   <span style="color: blue">BEGIN
      SELECT </span>@nextpos <span style="color: gray">= </span><span style="color: magenta">charindex</span><span style="color: gray">(</span><span style="color: red">','</span><span style="color: gray">, </span>@list<span style="color: gray">, </span>@pos <span style="color: gray">+ </span>1<span style="color: gray">)
      </span><span style="color: blue">SELECT </span>@valuelen <span style="color: gray">= </span><span style="color: blue">CASE WHEN </span>@nextpos <span style="color: gray">&gt; </span>0
                              <span style="color: blue">THEN </span>@nextpos
                              <span style="color: blue">ELSE </span><span style="color: magenta">len</span><span style="color: gray">(</span>@list<span style="color: gray">) + </span>1
                         <span style="color: blue">END </span><span style="color: gray">- </span>@pos <span style="color: gray">- </span>1
      <span style="color: blue">INSERT </span>@tbl <span style="color: gray">(</span>number<span style="color: gray">)
         </span><span style="color: blue">VALUES </span><span style="color: gray">(</span><span style="color: magenta">convert</span><span style="color: gray">(</span><span style="color: blue">int</span><span style="color: gray">, </span><span style="color: magenta">substring</span><span style="color: gray">(</span>@list<span style="color: gray">, </span>@pos <span style="color: gray">+ </span>1<span style="color: gray">, </span>@valuelen<span style="color: gray">)))
      </span><span style="color: blue">SELECT </span>@pos <span style="color: gray">= </span>@nextpos
   <span style="color: blue">END
  RETURN
END</span></pre>
<div>&#160;</div>
<p>It takes a list of comma-delimited integers and returns a resultset containing integers, just what we need!</p>
<p>When we implement this in our main procedure, this is what it looks like:</p>
<pre class="code"><span style="color: blue">ALTER PROCEDURE </span>GetEmployeeData
    @HireDate <span style="color: blue">date</span><span style="color: gray">,
    </span>@DepartmentList <span style="color: blue">varchar</span><span style="color: gray">(</span>1000<span style="color: gray">)
</span><span style="color: blue">AS
BEGIN
    SELECT </span>E<span style="color: gray">.</span>NationalIDNumber<span style="color: gray">, </span>E<span style="color: gray">.</span>JobTitle<span style="color: gray">, </span>E<span style="color: gray">.</span>BirthDate<span style="color: gray">, </span>E<span style="color: gray">.</span>MaritalStatus<span style="color: gray">, </span>E<span style="color: gray">.</span>Gender<span style="color: gray">,
        </span>E<span style="color: gray">.</span>HireDate<span style="color: gray">, </span>E<span style="color: gray">.</span>SalariedFlag<span style="color: gray">, </span>E<span style="color: gray">.</span>VacationHours<span style="color: gray">, </span>E<span style="color: gray">.</span>SickLeaveHours<span style="color: gray">,
        </span>D<span style="color: gray">.</span>GroupName <span style="color: blue">as </span>DepartmentGroupName<span style="color: gray">, </span>D<span style="color: gray">.</span>Name <span style="color: blue">as </span>DepartmentName<span style="color: gray">,
        </span>P<span style="color: gray">.</span>FirstName<span style="color: gray">, </span>P<span style="color: gray">.</span>MiddleName<span style="color: gray">, </span>P<span style="color: gray">.</span>LastName
    <span style="color: blue">FROM </span>HumanResources<span style="color: gray">.</span>Employee E
    <span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>EmployeeDepartmentHistory EDH
        <span style="color: blue">ON </span>EDH<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
        <span style="color: gray">AND </span>EDH<span style="color: gray">.</span>EndDate <span style="color: gray">IS NULL </span><span style="color: green">-- current active department does not have EndDate filled in
    </span><span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>Department D
        <span style="color: blue">ON </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">= </span>EDH<span style="color: gray">.</span>DepartmentID
    <span style="color: gray">INNER JOIN </span>Person<span style="color: gray">.</span>Person P
        <span style="color: blue">ON </span>P<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
    <span style="color: blue">WHERE </span>E<span style="color: gray">.</span>HireDate <span style="color: gray">&gt; </span>@HireDate
        <span style="color: gray">AND </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">IN (</span><span style="color: blue">select </span><span style="color: gray">* </span><span style="color: blue">from </span>list_to_tbl<span style="color: gray">(</span>@DepartmentList<span style="color: gray">));
</span><span style="color: blue">END</span></pre>
<div>&#160;</div>
<p>And indeed, if we now run our report again, it works perfectly!</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report using multivalue parameter" border="0" alt="Report using multivalue parameter" src="http://blog.hoegaerden.be/wp-content/uploads/image128.png" width="596" height="239" /> </p>
<p><b>Note:</b> for another great reference on how to deal with a delimited list as Stored Proc parameter, I&#8217;d like to point you to the following article by colleague Expert and SQL Server MVP <a title="angelIII - a Legendary EE member!" href="http://www.experts-exchange.com/M_302115.html">angelIII</a>: <a title="delimited list as parameter, what are the options?" href="http://www.experts-exchange.com/articles/Database/Miscellaneous/delimited-list-as-parameter-what-are-the-options.html">http://www.experts-exchange.com/articles/Database/Miscellaneous/delimited-list-as-parameter-what-are-the-options.html</a></p>
</p>
<h3>Displaying The Filter On The Report</h3>
<p>Another best practice as far as report readability goes is that it should be clear on your report what data has been filtered.&#160; As the multi-value parameter is on focus here, I’ll demonstrate how you can show the selected values on your report.</p>
<p>In fact, it’s not really the parameter’s values that we are interested in now (those are DepartmentIDs, remember?).&#160; No, it’s the labels.&#160; And here’s how to get to them.&#160; Add a new textbox above the main report table.&#160; Make it the same width as the table and right-click it to add an Expression.&#160; Enter the following expression:</p>
<div class="code"><font color="#0000ff">=Join</font><font color="#000000">(Parameters!DepartmentList.Label,</font><font color="#808080"> &quot;, &quot;</font><font color="#000000">)</font> </div>
<p>&#160;</p>
<p>It uses the Join function to join all members of the Label collection together into one string, using comma and space as the value separator.&#160; This is what it looks like on the report:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image129.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Showing selected values of a multi-value parameter on the report" border="0" alt="Showing selected values of a multi-value parameter on the report" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb32.png" width="675" height="245" /></a> </p>
<p>&#160;</p>
<p>In case you would like to see the selected departments under each other instead of in a long string, that’s also quite easy to achieve.&#160; The expression is based on Visual Basic, and in Visual Basic there’s a constant called vbCrLf – Visual Basic carriage-return line-feed.&#160; Adapt the expression to the following and the values will be shown in a list instead of a long string:</p>
<div class="code"><font color="#0000ff">=Join</font><font color="#000000">(Parameters!DepartmentList.Label,</font><font color="#808080">&#160;</font><font color="#000000">vbCrLf)</font> </div>
<div class="code">&#160;</div>
<div class="code">Let’s have another look at the effect:</div>
<div class="code">&#160;</div>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Showing selected values under each other" border="0" alt="Showing selected values under each other" src="http://blog.hoegaerden.be/wp-content/uploads/image130.png" width="604" height="268" /> </p>
<p>&#160;</p>
<h2>Conclusion</h2>
<p>With this article I believe I’ve demonstrated that it is possible to pass multi-value parameters from a SQL Server Reporting Services report to a stored procedure, while applying some best practices such as giving the users a nice list of values to select from.&#160; </p>
<p>Happy reporting, thank you for reading my article, and should you feel like it: post a comment!</p>
<p>Valentino.</p>
</p>
</p>
<p><strong>References</strong></p>
<p><a title="BOL 2008: the IN operator" href="http://msdn.microsoft.com/en-us/library/ms177682.aspx" target="_blank">BOL 2008: the IN operator</a></p>
<p><a title="The Curse and Blessings of Dynamic SQL" href="http://www.sommarskog.se/dynamic_sql.html" target="_blank">The Curse and Blessings of Dynamic SQL</a> by Erland Sommarskog, SQL Server MVP</p>
<p><a title="Arrays and Lists in SQL Server 2005" href="http://www.sommarskog.se/arrays-in-sql-2005.html" target="_blank">Arrays and Lists in SQL Server 2005</a> by Erland Sommarskog, SQL Server MVP</p>
</p>
</p>
<p><a title="BOL 2008: Expression Examples (Reporting Services)" href="http://msdn.microsoft.com/en-us/library/ms157328.aspx" target="_blank">BOL 2008: Expression Examples (Reporting Services)</a></p>
<p><a title="delimited list as parameter, what are the options?" href="http://www.experts-exchange.com/articles/Database/Miscellaneous/delimited-list-as-parameter-what-are-the-options.html">delimited list as parameter, what are the options?</a> by <a title="angelIII - a Legendary EE member!" href="http://www.experts-exchange.com/M_302115.html">angelIII</a>, SQL Server MVP</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2009/11/21/reporting-on-data-from-stored-procedures-part-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Reporting On Data From Stored Procedures (part 1)</title>
		<link>http://blog.hoegaerden.be/2009/11/10/reporting-on-data-from-stored-procedures-part-1/</link>
		<comments>http://blog.hoegaerden.be/2009/11/10/reporting-on-data-from-stored-procedures-part-1/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 12:35:14 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2009/11/10/reporting-on-data-from-stored-procedures-part-1/</guid>
		<description><![CDATA[Introduction
The first step of creating a SQL Server Reporting Services (SSRS) report involves setting up a connection to the data source and programming a dataset to retrieve data from that data source.&#160; The dataset can use a SELECT query, which is the most common way of retrieving data and one that you’re probably already familiar [...]]]></description>
			<content:encoded><![CDATA[<h2>Introduction</h2>
<p>The first step of creating a SQL Server Reporting Services (SSRS) report involves setting up a connection to the data source and programming a dataset to retrieve data from that data source.&#160; The dataset can use a SELECT query, which is the most common way of retrieving data and one that you’re probably already familiar with.&#160; But it can also use a Stored Procedure (aka stored proc or SP).</p>
<p>The purpose of this article is to demonstrate how data can be retrieved from a SQL Server database through Stored Procedures defined in that same database, and then displayed in a SQL Server 2008 Reporting Services report.</p>
<p>I’ll be using the AdventureWorks2008 sample database available for download at <a title="SQL Server sample databases at CodePlex" href="http://www.codeplex.com/MSFTDBProdSamples" target="_blank">CodePlex</a>.</p>
<h2>What Are Stored Procedures?</h2>
<p>There are actually different types of stored procedure in the context of SQL Server.&#160; The type that I am using in this article is called a “Transact-SQL Stored Procedure”.&#160; According to the <a title="BOL 2008 - Types of Stored Procedures" href="http://msdn.microsoft.com/en-us/library/ms187644.aspx" target="_blank">Books Online</a>, this type of stored procedure is:</p>
<blockquote><p>“A saved collection of Transact-SQL statements that can take and return user-supplied parameters.”</p>
</blockquote>
<p>If you have experience using a regular programming language such as Visual Basic or C#, I’m sure this sounds familiar.&#160; You can think of a stored procedure as a method that takes any number of parameters, depending on its definition, and that possibly returns a result, again depending on its definition.&#160; Instead of being stored in a compiled .exe or .dll, it is stored in the database.</p>
<p>In this article I will be using some stored procedures that return a dataset as result.&#160; How stored procedures are written is not the purpose of this article.&#160; For that I’d like to refer you to this Books Online page: <a title="BOL 2008 - Implementing Stored Procedures" href="http://msdn.microsoft.com/en-us/library/ms187451.aspx" target="_blank">Implementing Stored Procedures</a>.</p>
<h2>Reasons For Using A Stored Procedure</h2>
<p>There are several reasons why it is more interesting to use datasets based on stored procedures as opposed to SELECT statements.</p>
<p><strong>Performance:</strong> stored procedures perform faster than SELECT statements.&#160; The reason for this is because they are compiled when they’re created and their execution plan gets stored by SQL Server so that it can be reused for each procedure call.</p>
<p><strong>Maintenance:</strong> when a database needs to undergo some changes to its schema, the changes can be handled in the stored procedures.&#160; This makes it transparent for the reports that are using these stored procedures.&#160; The reports will keep functioning as expected without any modifications to them.</p>
<p><strong>Reuse:</strong> imagine a situation where several reports are reporting on the same set of data.&#160; If you wouldn’t use stored procedures, you may have to repeat a possibly complex query in each report.&#160; With stored procedures you just need to define the query in the stored procedure and then call it in each report’s dataset.</p>
<p><strong>Security:</strong> in environments where DBAs are responsible for the SQL Server databases, the report developers will possibly not get sufficient rights to retrieve data from the tables directly.&#160; One of the ways to prevent this is to give them access to a bunch of stored procedures and views instead.</p>
<h2>Simple Procedure Call</h2>
<p>Okay, enough theory, time to show you how it’s done!</p>
<h3>Setting Up The Stored Procedure</h3>
<p>Our first procedure queries the AdventureWorks database to return a list of employees with their corresponding department.&#160; Here’s the code for the SP:</p>
<pre class="code"><span style="color: blue">CREATE PROCEDURE </span>GetEmployeeData
<span style="color: blue">AS
BEGIN
    SELECT </span>E<span style="color: gray">.</span>NationalIDNumber<span style="color: gray">, </span>E<span style="color: gray">.</span>JobTitle<span style="color: gray">, </span>E<span style="color: gray">.</span>BirthDate<span style="color: gray">, </span>E<span style="color: gray">.</span>MaritalStatus<span style="color: gray">, </span>E<span style="color: gray">.</span>Gender<span style="color: gray">,
        </span>E<span style="color: gray">.</span>HireDate<span style="color: gray">, </span>E<span style="color: gray">.</span>SalariedFlag<span style="color: gray">, </span>E<span style="color: gray">.</span>VacationHours<span style="color: gray">, </span>E<span style="color: gray">.</span>SickLeaveHours<span style="color: gray">,
        </span>D<span style="color: gray">.</span>GroupName <span style="color: blue">as </span>DepartmentGroupName<span style="color: gray">, </span>D<span style="color: gray">.</span>Name <span style="color: blue">as </span>DepartmentName<span style="color: gray">,
        </span>P<span style="color: gray">.</span>FirstName<span style="color: gray">, </span>P<span style="color: gray">.</span>MiddleName<span style="color: gray">, </span>P<span style="color: gray">.</span>LastName
    <span style="color: blue">FROM </span>HumanResources<span style="color: gray">.</span>Employee E
    <span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>EmployeeDepartmentHistory EDH
        <span style="color: blue">ON </span>EDH<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
        <span style="color: gray">AND </span>EDH<span style="color: gray">.</span>EndDate <span style="color: gray">IS NULL </span><span style="color: green">-- current active department does not have EndDate filled in
    </span><span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>Department D
        <span style="color: blue">ON </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">= </span>EDH<span style="color: gray">.</span>DepartmentID
    <span style="color: gray">INNER JOIN </span>Person<span style="color: gray">.</span>Person P
        <span style="color: blue">ON </span>P<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID<span style="color: gray">;
</span><span style="color: blue">END</span></pre>
</p>
<h3>Creating The Report</h3>
<div>The next step is to create a new Report in a Report Server project using Business Intelligence Development Studio 2008 (aka BIDS).&#160; To add a report my preferred way is to right-click the Reports folder in the Solution Explorer (this is assuming that you’ve already created a Report Server project) and then select Add &gt; New Item… :</div>
<div>&#160;</div>
<div><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Creating a new Reporting Services report" border="0" alt="Creating a new Reporting Services report" src="http://blog.hoegaerden.be/wp-content/uploads/image99.png" width="339" height="111" /> </div>
<div>&#160;</div>
<div>Make sure that the Report template is selected.&#160; I’m calling my report StoredProcDataset.</div>
<div>&#160;</div>
<div><a href="http://blog.hoegaerden.be/wp-content/uploads/image100.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Add New Item - Report" border="0" alt="Add New Item - Report" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb19.png" width="532" height="328" /></a> </div>
<div>&#160;</div>
<h3>Creating A Shared Data Source</h3>
<div>Now that we’ve got an empty report we still need to get some data.&#160; We’ll set up a Shared Data Source first.&#160; Shared Data Sources are convenient when you’re planning to create several reports on the same database.&#160; It removes the connection string from the report itself and puts it in a separate Shared Data Source object, making it easy to switch between databases.&#160; (Imagine putting your reports into the production environment – instead of needing to modify each report to connect to the production database, you just need to modify the Shared Data Source).</div>
<div>&#160;</div>
<div>In the Solution Explorer, right-click the Shared Data Sources folder and select <strong>Add New Data Source</strong>.</div>
<div>&#160;</div>
<div><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Solution Explorer Shared Data Sources - Add New Data Source" border="0" alt="Solution Explorer Shared Data Sources - Add New Data Source" src="http://blog.hoegaerden.be/wp-content/uploads/image101.png" width="227" height="131" /> </div>
<div>&#160;</div>
<div>&#160;</div>
<div><a href="http://blog.hoegaerden.be/wp-content/uploads/image102.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Shared Data Source Properties" border="0" alt="Shared Data Source Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb20.png" width="525" height="435" /></a> </div>
<div>&#160;</div>
<div>I’m calling the Shared Data Source AdventureWorks2008.&#160; A Data Source can connect to several different sources, such as Oracle or an Analysis Services cube.&#160; In fact, it can connect to any source through OLE DB, as long as there’s an OLE DB provider that has all the expected functionality implemented.&#160; For a good list of drivers, have a look at the Books Online: <a title="BOL 2008 - Data Sources Supported by Reporting Services" href="http://msdn.microsoft.com/en-us/library/ms159219.aspx" target="_blank">Data Sources Supported by Reporting Services</a>.</div>
<div>&#160;</div>
<div>The one that we’re interested in now is called Microsoft SQL Server, which is by default selected in the Type dropdown.</div>
<div>&#160;</div>
<h3>Creating The Data Source</h3>
<div>Next we’ll add a Data Source to the report based on the Shared Data Source.</div>
<div>&#160;</div>
<div><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Data pane - New Data Source" border="0" alt="Report Data pane - New Data Source" src="http://blog.hoegaerden.be/wp-content/uploads/image103.png" width="163" height="133" /> </div>
<div>&#160;</div>
<div>In the Report Data pane, select <strong>New &gt; Data Source…</strong>.</div>
<div>&#160;</div>
<div>If you don’t see the Report Data pane, you can open it by going to the View menu item and selecting Report Data right down at the bottom of the menu window.&#160; Or hit CTRL + ALT + D.&#160; That’s an interesting shortcut to memorize because the Report Data pane has a tendency to disappear, especially if you’ve closed and re-opened the BIDS.</div>
<div>&#160;</div>
<div><a href="http://blog.hoegaerden.be/wp-content/uploads/image104.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Data Source Properties" border="0" alt="Data Source Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb21.png" width="525" height="435" /></a> </div>
<div>&#160;</div>
<div>I’ve called my Data Source srcAdventureWorks2008 and I’ve told it to use the existing Shared Data Source.</div>
<div>&#160;</div>
<h3>Creating The Dataset</h3>
<div>So, now we’re ready to query our stored procedure.&#160; In the Report Data pane, right-click the newly created Data Source and select <strong>Add Dataset…</strong>.</div>
<div>&#160;</div>
<div><a href="http://blog.hoegaerden.be/wp-content/uploads/image105.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Right-click Data Source to Add Dataset" border="0" alt="Right-click Data Source to Add Dataset" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb22.png" width="300" height="188" /></a> </div>
<p>&#160;</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image106.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Dataset Properties" border="0" alt="Dataset Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb23.png" width="530" height="439" /></a> </p>
<p>I’m calling the Dataset dsEmployeeData.&#160; The Data Source edit box is already prefilled with the right data source because we’ve right-clicked the data source to which we want to add a dataset, how easy can it be?</p>
<p>To query a stored procedure from a dataset is really very straightforward.&#160; All you need to do now is select the <strong>Stored Procedure radio button</strong>.&#160; Doing that replaces the bottom part of the window.&#160; Instead of an edit box that expects a query, we now get a simple dropdown where we need to select our SP.</p>
<p>Once you’ve done that, select the <strong>Fields</strong> page on the left.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image107.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Dataset Properties - Fields" border="0" alt="Dataset Properties - Fields" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb24.png" width="527" height="572" /></a> </p>
<p>As you can see, the list of fields has been pre-filled.&#160; The BIDS queries the stored procedure’s metadata so we do not need to manually specify the fields returned by our SP, saving us quite some time!</p>
<p>Once you click OK to close the Dataset Properties window, you’ll see that the Report Data pane gets populated with our list of fields.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Data pane - list of fields in dataset" border="0" alt="Report Data pane - list of fields in dataset" src="http://blog.hoegaerden.be/wp-content/uploads/image108.png" width="202" height="358" /> </p>
<h3>Show Me The Data</h3>
<p>To prove that everything is working as expected, let’s set up a quick report using a Table.&#160; From the Toolbox pane, drag a <strong>Table</strong> object onto the report canvas:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report with a Table" border="0" alt="Report with a Table" src="http://blog.hoegaerden.be/wp-content/uploads/image109.png" width="348" height="207" /> </p>
<p>Next, from the Report Data pane, drag some fields into the cells in the Data part of the Table.&#160; As we’re dealing with employee data, it would be interesting to see their names.&#160; I’ve also added their job and department.</p>
<p>Resize the columns a bit so that everything will fit nicely, and color the Header cells different from the Data cells to easily distinguish them.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image110.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Table with some fields added and basic layout" border="0" alt="Table with some fields added and basic layout" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb25.png" width="553" height="74" /></a> </p>
<p>Now we’re ready to run the report, so click the Report’s Preview tab.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image111.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Table showing some employee data" border="0" alt="Table showing some employee data" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb26.png" width="550" height="238" /></a> </p>
<p>So, that was our first procedure.&#160; Wasn’t too complicated, was it?&#160; So, ready for another one?</p>
<h2>Parameterized Procedure Call</h2>
<p>This time we’ll make it a little more complicated.&#160; As you know, stored procedures can take parameters.&#160; And SSRS knows how to pass them into a stored proc.&#160; So let’s do that!</p>
<h3>Setting Up Stored Proc Version 2.0</h3>
<p>The stored procedure shown below is based on our previous one.&#160; Except now it takes one parameter: @HireDate.&#160; The SP will only return employees that have been hired after given HireDate.</p>
<pre class="code"><span style="color: blue">ALTER PROCEDURE </span>GetEmployeeData
    @HireDate <span style="color: blue">date
AS
BEGIN
    SELECT </span>E<span style="color: gray">.</span>NationalIDNumber<span style="color: gray">, </span>E<span style="color: gray">.</span>JobTitle<span style="color: gray">, </span>E<span style="color: gray">.</span>BirthDate<span style="color: gray">, </span>E<span style="color: gray">.</span>MaritalStatus<span style="color: gray">, </span>E<span style="color: gray">.</span>Gender<span style="color: gray">,
        </span>E<span style="color: gray">.</span>HireDate<span style="color: gray">, </span>E<span style="color: gray">.</span>SalariedFlag<span style="color: gray">, </span>E<span style="color: gray">.</span>VacationHours<span style="color: gray">, </span>E<span style="color: gray">.</span>SickLeaveHours<span style="color: gray">,
        </span>D<span style="color: gray">.</span>GroupName <span style="color: blue">as </span>DepartmentGroupName<span style="color: gray">, </span>D<span style="color: gray">.</span>Name <span style="color: blue">as </span>DepartmentName<span style="color: gray">,
        </span>P<span style="color: gray">.</span>FirstName<span style="color: gray">, </span>P<span style="color: gray">.</span>MiddleName<span style="color: gray">, </span>P<span style="color: gray">.</span>LastName
    <span style="color: blue">FROM </span>HumanResources<span style="color: gray">.</span>Employee E
    <span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>EmployeeDepartmentHistory EDH
        <span style="color: blue">ON </span>EDH<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
        <span style="color: gray">AND </span>EDH<span style="color: gray">.</span>EndDate <span style="color: gray">IS NULL </span><span style="color: green">-- current active department does not have EndDate filled in
    </span><span style="color: gray">INNER JOIN </span>HumanResources<span style="color: gray">.</span>Department D
        <span style="color: blue">ON </span>D<span style="color: gray">.</span>DepartmentID <span style="color: gray">= </span>EDH<span style="color: gray">.</span>DepartmentID
    <span style="color: gray">INNER JOIN </span>Person<span style="color: gray">.</span>Person P
        <span style="color: blue">ON </span>P<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>E<span style="color: gray">.</span>BusinessEntityID
    <span style="color: blue">WHERE </span>E<span style="color: gray">.</span>HireDate <span style="color: gray">&gt; </span>@HireDate<span style="color: gray">;
</span><span style="color: blue">END</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<div>&#160;</div>
<p>As the HireDate field in the HumanResources.Employee table is of type <a title="BOL 2008 - date data type" href="http://msdn.microsoft.com/en-us/library/bb630352.aspx" target="_blank">date</a>, I chose to make the parameter that same data type.</p>
<p>Please note that the above script uses <a title="BOL 2008 - ALTER PROCEDURE" href="http://msdn.microsoft.com/en-us/library/bb630352.aspx" target="_blank">ALTER PROCEDURE</a> instead of CREATE PROCEDURE.&#160; This will only work if you’ve already created the previous procedure.&#160; If not, just replace the word ALTER with CREATE.</p>
<h3>Modify Report To Pass Parameter To Stored Procedure</h3>
<p>The next step is to modify our existing Dataset so that it passes a date into our stored procedure.</p>
<p>Open up the Dataset’s properties by double-clicking it in the Report Data pane.&#160; Then select the Parameters page:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image112.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Dataset Properties - Parameters empty" border="0" alt="Dataset Properties - Parameters empty" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb27.png" width="557" height="462" /></a> </p>
<p>As you can see, it is still empty.</p>
<p>Now switch to the Query page and click the <strong>Refresh Fields…</strong> button:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Dataset Properties - Query page - Refresh Fields button" border="0" alt="Dataset Properties - Query page - Refresh Fields button" src="http://blog.hoegaerden.be/wp-content/uploads/image113.png" width="443" height="82" /> </p>
<p>Then switch back to the Parameters page:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image114.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Dataset Properties - Parameters page populated" border="0" alt="Dataset Properties - Parameters page populated" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb28.png" width="554" height="459" /></a> </p>
<p>The parameter has been automatically added when we clicked the Refresh Fields… button!</p>
<p>The BIDS again used the stored proc’s metadata to do this.&#160; No need for manual intervention.&#160; For now, leave the <strong>Parameter Value</strong> box as it is, empty.&#160; Click OK to close the properties window.</p>
<p>Clicking OK caused another action in our report!&#160; If you open up the Parameters folder in the Report Data pane, you’ll see that it has gotten an item as well:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Data pane - Parameters" border="0" alt="Report Data pane - Parameters" src="http://blog.hoegaerden.be/wp-content/uploads/image115.png" width="172" height="173" /> </p>
<p>You can double-click the @HireDate parameter to get its properties:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image116.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Parameter Properties" border="0" alt="Report Parameter Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb29.png" width="548" height="454" /></a> </p>
<p>The BIDS has created a report parameter and linked it to the parameter in our Dataset.&#160; It automatically chooses the correct data type for the report parameter, <strong>Date/Time</strong> in this case.&#160; (Unlike in T-SQL, there are no separate Date and Time data types in SSRS 2008.)</p>
<p>To confirm that the report parameter is linked to the parameter in the Dataset, close the Report Parameter Properties window and open up the Dataset Properties again, selecting the Parameters page:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image117.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Dataset Properties - Parameters page - Parameter Value filled in" border="0" alt="Dataset Properties - Parameters page - Parameter Value filled in" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb30.png" width="554" height="434" /></a> </p>
<p>The <strong>Parameter Value</strong> for our parameter has now gotten a value, more precisely it’s referring to the Report Parameter called @HireDate.&#160; If you don’t believe that it is actually the report parameter (I admit, it looks similar to the parameter in the Dataset, except for the square brackets surrounding the report parameter’s name.), click the fx button to see the formula:</p>
<div class="code"><font color="#0000ff">=</font><font color="#000000">Parameters!HireDate.Value</font></div>
<div class="code">&#160;</div>
<div class="code"><font color="#000000"></font></div>
<p>Indeed, it is referring to the parameter on the report.</p>
<h3>Test The Changes</h3>
<p>Now that the parameter has been set up, it’s time to test our report again.</p>
<p>As the report is now filtering on the HireDate, it would be interesting to actually show this field in the table.&#160; Add an extra column and drag this field into the data cell.</p>
<p>Our newly added field’s type is <strong>datetime</strong>, but we’re only interested in the date part.&#160; So we’ll set up a format code.&#160; Select the HireDate data cell and locate the <strong>Format</strong> property in the Properties pane.&#160; Enter a small d into it:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Formatting a datetime to only show the date" border="0" alt="Formatting a datetime to only show the date" src="http://blog.hoegaerden.be/wp-content/uploads/image118.png" width="306" height="134" /> </p>
<p>This instructs the BIDS to show the field using the “short date pattern”.&#160; A list of possible codes is available on MSDN: <a title="VS 2008 - Standard Date and Time Format Strings" href="http://msdn.microsoft.com/en-us/library/az4se3k1.aspx" target="_blank">Standard Date and Time Format Strings</a>.&#160; As you notice, SSRS is using the regular formatting strings as they are known in .NET.</p>
<p>Note also that the format used to display the data depends on the report’s <strong>Language</strong> property.&#160; I’ll leave it at its default: en-US.</p>
<p>Right, time to have a look at the report.&#160; Select the Preview tab.&#160; You can now see the Hire Date parameter which is expecting a value.&#160; You can either type a value or select it from the calendar which is shown when you click the button on the right of the textbox:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Calendar control for a datetime report parameter" border="0" alt="Calendar control for a datetime report parameter" src="http://blog.hoegaerden.be/wp-content/uploads/image119.png" width="229" height="213" /> </p>
<p>To be sure that you’re using the correct format for the date, I suggest to select a date using the control.&#160; Then you can always modify it to whatever day you’d like to select.</p>
<p>For our test I know that some employees started before 2000 and others later, so I’ll select a date somewhere in the year 2000.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image120.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report with datetime filter" border="0" alt="Report with datetime filter" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb31.png" width="553" height="300" /></a> </p>
<p>And indeed, our report shows only employees that started after our selected HireDate.</p>
<h2>Conclusion</h2>
<p>With this article I hope to have shown you that it’s fairly straightforward to report on data coming from stored procedures.</p>
<p>In case the above hasn’t fulfilled your appetite on this subject yet, watch out for <a title="Reporting On Data From Stored Procedures (part 2)" href="http://blog.hoegaerden.be/2009/11/21/reporting-on-data-from-stored-procedures-part-2/">part 2</a>.&#160; In that sequel I will build further on the example used in this article to show you how you can use multi-value parameters to filter your report’s data.</p>
<p>In the meantime: happy reporting, and thank you for reading my article!</p>
<p><strong>References</strong></p>
<p><a title="BOL 2008 - How to: Create an Embedded or Shared Data Source" href="http://msdn.microsoft.com/en-us/library/ms159165.aspx" target="_blank">BOL 2008 &#8211; How to: Create an Embedded or Shared Data Source</a></p>
<p><a title="BOL 2008 - How to: Create a Dataset (Reporting Services)" href="http://msdn.microsoft.com/en-us/library/ms160345.aspx" target="_blank">BOL 2008 &#8211; How to: Create a Dataset (Reporting Services)</a></p>
<p><a title="BOL 2008 - How to: Refresh Fields for a Dataset" href="http://msdn.microsoft.com/en-us/library/ms365160.aspx" target="_blank">BOL 2008 &#8211; How to: Refresh Fields for a Dataset</a></p>
<p><a title="BOL 2008 - Implementing Stored Procedures" href="http://msdn.microsoft.com/en-us/library/ms187451.aspx" target="_blank">BOL 2008 &#8211; Implementing Stored Procedures</a></p>
<p><a title="BOL 2008 - Data Sources Supported by Reporting Services" href="http://msdn.microsoft.com/en-us/library/ms159219.aspx" target="_blank">BOL 2008 &#8211; Data Sources Supported by Reporting Services</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2009/11/10/reporting-on-data-from-stored-procedures-part-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Pie Chart Techniques</title>
		<link>http://blog.hoegaerden.be/2009/10/25/pie-chart-techniques/</link>
		<comments>http://blog.hoegaerden.be/2009/10/25/pie-chart-techniques/#comments</comments>
		<pubDate>Sun, 25 Oct 2009 13:26:55 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[Charting]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2009/10/25/pie-chart-techniques/</guid>
		<description><![CDATA[A while ago I wrote an article called Chart Optimization Tips.&#160; This article explained how to optimize a Column Chart.&#160; Today I have returned to show you some Pie Chart implementation techniques.
As usual, I will be using the AdventureWorks2008 database, available at CodePlex.&#160; The chart itself will be implemented using SQL Server 2008 Reporting Services.
Retrieving [...]]]></description>
			<content:encoded><![CDATA[<p>A while ago I wrote an article called <a title="Chart Optimization Tips" href="http://blog.hoegaerden.be/2009/07/20/chart-optimization-tips/" target="_blank">Chart Optimization Tips</a>.&#160; This article explained how to optimize a Column Chart.&#160; Today I have returned to show you some Pie Chart implementation techniques.</p>
<p>As usual, I will be using the AdventureWorks2008 database, available at <a title="SQL Server sample databases at CodePlex" href="http://www.codeplex.com/MSFTDBProdSamples" target="_blank">CodePlex</a>.&#160; The chart itself will be implemented using SQL Server 2008 Reporting Services.</p>
<h2>Retrieving The Data</h2>
<p>The dataset in our report uses the following query:</p>
<pre class="code"><span style="color: blue">select </span>SWD<span style="color: gray">.*, </span>SWA<span style="color: gray">.</span>City<span style="color: gray">, </span>SWA<span style="color: gray">.</span>StateProvinceName<span style="color: gray">,
    </span>SWA<span style="color: gray">.</span>PostalCode<span style="color: gray">, </span>SWA<span style="color: gray">.</span>CountryRegionName<span style="color: gray">, </span>SWA<span style="color: gray">.</span>AddressType
<span style="color: blue">from </span>Sales<span style="color: gray">.</span>vStoreWithDemographics SWD
<span style="color: gray">inner join </span>Sales<span style="color: gray">.</span>vStoreWithAddresses SWA
    <span style="color: blue">on </span>SWA<span style="color: gray">.</span>BusinessEntityID <span style="color: gray">= </span>SWD<span style="color: gray">.</span>BusinessEntityID</pre>
<p>This query illustrates a bad coding practice: never use “SELECT *”.&#160; Ideally you should only retrieve the columns that you need for the report.&#160; That will optimize performance when generating the report.&#160; But that is not the goal of this article so I’ll leave the query as it is.</p>
<h2>A Basic Pie Chart</h2>
<p>To get started with our Pie Chart I have selected the third icon in the list of Shape charts.&#160; This adds a regular 3D pie chart to the report.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image78.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Select Chart Type window" border="0" alt="Select Chart Type window" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb5.png" width="546" height="489" /></a></p>
<p>To set up the chart I dragged AnnualSales from the Report Data pane into the “Drop data fields here” area and StateProvinceName into the “Drop category fields here”.</p>
<p>In case you don’t see the Report Data view (it has a tendency to disappear now and then), you can open it through the main menu: View &gt; Report Data.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report Data Pane" border="0" alt="Report Data Pane" src="http://blog.hoegaerden.be/wp-content/uploads/image79.png" width="290" height="450" /></p>
<p>This is what our report looks like in Preview:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image80.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Basic Pie Chart" border="0" alt="Basic Pie Chart" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb6.png" width="551" height="367" /></a></p>
<p>Wow, we’ve still got some work to do, this looks like a kids color book!&#160; You wouldn’t say that this chart is showing the annual sales, would you?&#160; There aren’t even any numbers on it!&#160; Let’s get started on improving this.</p>
<h2>Sorting The Numbers</h2>
<p>A good implementation practice is to sort the slices from large to small.&#160; If the slices are not sorted, it’s difficult to tell which state is performing better than another.&#160; Just take a look at the previous image and compare the following two slices:</p>
<ul>
<li>the pie shown in grey at 12:00 </li>
<li>the pie shown in yellow at 03:00 </li>
</ul>
<p>Which one is the larger of the two?&#160; Indeed, “I don’t know” is the right answer.</p>
<p>To implement the sorting you need to think about what you want to achieve.&#160; What is it that we want to sort?&#160; The states.&#160; And these are shown as categories on the chart, so we should take a look at its properties.&#160; As shown in the following screenshot, right-clicking on the [StateProvinceName] button gives a pop-up menu.&#160; Select Category Group Properties.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image81.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Context menu for Category Group" border="0" alt="Context menu for Category Group" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb7.png" width="475" height="99" /></a></p>
<p>Then we need to think about how we want the states to get sorted.&#160; For that we should look at what is being shown as data of the chart.&#160; In our case that is the sum of the AnnualSales field.</p>
<p>In the Category Group Properties, select the page called Sorting.&#160; Clicking the Add button will add a line in the sorting options list.&#160; Use the following expression for the “Sort by” field:</p>
<pre class="code">=Sum(Fields!AnnualSales.Value)</pre>
<p>As we want to sort the largest values first, select “Z to A” for the Order dropdown.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image82.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Category Group Properties" border="0" alt="Category Group Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb8.png" width="476" height="394" /></a></p>
<p>Right, time to have another look at our report in Preview.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image83.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Sorted Pie Chart" border="0" alt="Sorted Pie Chart" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb9.png" width="557" height="367" /></a></p>
<p>So, we went from a colorful mess to an ordered colorful mess.&#160; Chaos has been reduced a bit, but this is still one difficult-to-read report.</p>
<p>On to the next improvement!</p>
<h2>Limiting The Pies</h2>
<p>As you have noticed, a pie chart is not suitable to show that many categories.&#160; We need to find a way to reduce the slices.&#160; One way to do that is by adding a filter.&#160; Another way is to add the smallest slices together into one slice.&#160; This can be interesting in cases where we want to use all the data but we’re only interested in the larger slices.&#160; Luckily, this can be done using standard pie chart properties.</p>
<p>Click on the pie itself, this will select the Chart Series.&#160; One way to tell if you’ve selected the correct part of the chart is by looking at the Properties pane.&#160; Its selection should show something like “<strong>AnnualSales</strong> Chart Series”, where <strong>AnnualSales</strong> is the name of the chart series.&#160; Another way to tell is by the small white selector bulbs: they should be surrounding the pie.</p>
<p>Now, among the properties of the Chart Series you will find a property group called CustomAttributes.&#160; Open this one by clicking the plus icon in front of it.&#160; Change the <strong>CollectedStyle</strong> property to SingleSlice.&#160; This tells the chart that we want to group the smallest slices into one slice.</p>
<p>Other interesting properties here are <strong>CollectedThreshold </strong>and <strong>CollectedThresholdUsePercent</strong>.&#160; I’ve put CollectedThreshold to 2 and CollectedThresholdUsePercent to True (which is its default).&#160; This means that any slice smaller than 2 percent of the pie will be added into the “collected slice”.</p>
<p>More useful properties are <strong>CollectedLabel</strong>, that’s the text that is shown on the slice itself, and <strong>CollectedLegendText</strong>, the text shown in the legend.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Chart Series - collected slice properties" border="0" alt="Chart Series - collected slice properties" src="http://blog.hoegaerden.be/wp-content/uploads/image84.png" width="382" height="248" /></p>
<p>The CollectedStyle property has another option besides the one I’ve shown, called CollectedPie.&#160; Choosing that will generate a second pie next to the main one to represent all the small slices.&#160; See the following screenshot for what it looks like.&#160; In some cases this may be an interesting option but not in our example here.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image85.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie Chart showing a CollectedPie" border="0" alt="Pie Chart showing a CollectedPie" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb10.png" width="599" height="339" /></a></p>
<p>The collected pie can also show labels by setting the <strong>CollectedChartShowLabels </strong>property to True, and the categories shown on the collected pie can be shown in the pie’s legend by setting <strong>CollectedChartShowLegend </strong>to True.</p>
<p>If you’d like the collected slice to jump out, there’s a property called <strong>CollectedSliceExploded</strong>.&#160; Setting it to True will produce something like the following:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Exploded Collected Slice" border="0" alt="Exploded Collected Slice" src="http://blog.hoegaerden.be/wp-content/uploads/image86.png" width="424" height="387" /></p>
<p>As you have noticed, the previous screenshots have started to show text on the slices.&#160; This can be easily activated by right-clicking the pie and selecting the Show Data Labels menu item.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Context menu on pie chart - Show Data Labels" border="0" alt="Context menu on pie chart - Show Data Labels" src="http://blog.hoegaerden.be/wp-content/uploads/image87.png" width="196" height="154" /></p>
<p>And the next screenshot shows what our chart currently looks like.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image88.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie chart with collected slice" border="0" alt="Pie chart with collected slice" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb11.png" width="552" height="395" /></a></p>
<p>The small slices have been replaced by a really large one, and the text on the large slice is our customized version.&#160; The other slices are showing some rather large numbers, so we still have some work to do.</p>
<h2>Displaying Percentages</h2>
<p>Let’s customize the label shown on the slices.&#160; As the numbers are really large, I recommend to divide them by 1,000.&#160; As long as it’s clearly mentioned on the report, it will make everything more readable.</p>
<p>Furthermore I’ll show you how to use built-in chart keywords (only available to ToolTips, custom legend text, and data point label properties), such as #PERCENT.</p>
<p>Right-click on one of the data labels and select Series Label Properties.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Context menu of data labels - Series Label Properties" border="0" alt="Context menu of data labels - Series Label Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image89.png" width="255" height="156" /></p>
<p>Click the expression (fx) button on the General page and enter the following expression:</p>
<pre class="code">=FormatCurrency(Sum(Fields!AnnualSales.Value) / 1000, 0) &amp; <span style="color: #a31515">&quot; (#PERCENT{P1})&quot;</span></pre>
<p>The first part divides the sum of AnnualSales by 1,000 and then applies the FormatCurrency function to the result.&#160; The second parameter for FormatCurrency tells the function that we don’t want any decimals.&#160; The result of this function call is concatenated with the second part using Visual Basic string concatenation (&amp;).</p>
<p>The second part looks like a regular string but it contains a built-in keyword: #PERCENT.&#160; This will show the percentage that the slice represents.&#160; Furthermore, there’s a custom string formatter appended: P1.&#160; By default the percentage would show 2 decimals.&#160; This way it will only use one digit for the decimal fraction.</p>
<p>See <a title="SQL Server 2008 BOL - Formatting Data Points on a Chart" href="http://msdn.microsoft.com/en-us/library/bb677551.aspx" target="_blank">here</a> for a list of all built-in keywords and <a title=".NET Formatting Types" href="http://msdn.microsoft.com/en-us/library/fbxft59x.aspx" target="_blank">this page</a> for more information on the available formatting options.</p>
<p>And following screenshot shows what our chart now looks like.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image90.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie chart showing percentages on slices" border="0" alt="Pie chart showing percentages on slices" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb12.png" width="579" height="413" /></a></p>
<p>I’ve also given it a clear title, decreased the Data Label font size to 8 and moved the legend down.</p>
<p>To move the legend: right-click it, select Legend Properties and play with the radio buttons for the Legend Position.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image91.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Legend Properties" border="0" alt="Legend Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb13.png" width="463" height="425" /></a></p>
<p>So, we’ve now got a fairly readable chart.&#160; It’s not perfect, some labels are overlapping, but it’s doable.&#160; However, we won’t rest here.&#160; On to the next tip.</p>
<h2>Rotating The Pie</h2>
<p>Some people may ask you, “Why on earth does the first slice (the blue one representing 10.6% in our example) start at this weird angle at 4 o’clock?&#160; Why can’t it start at 12:00?”.</p>
<p>Again we’re lucky because this can be controlled using a standard property.&#160; Among the Chart Series CustomAttributes property group there are still some properties which haven’t been mentioned earlier.&#160; One of them is called <strong>PieStartAngle</strong>.&#160; By default it is set to zero.&#160; Funny enough, zero stands for 30°.&#160; Try it out and enter 30 for the property value.&#160; Did you see the effect?&#160; Indeed, nothing happens!&#160; Now enter 90.&#160; Did you see the chart rotate, even in Design mode?&#160; Switch to Preview to get a better view of what the impact is.&#160; As you can see, setting it to 90 will cause the first slice to start at 06:00.&#160; To make it start at 12:00, we thus need to set the property to 270 degrees.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image92.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie Chart with customized rotation angle" border="0" alt="Pie Chart with customized rotation angle" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb14.png" width="599" height="427" /></a></p>
<h2>Labels Outside Pie Chart</h2>
<p>Other people may tell you, “But I don’t want all these labels on the pie itself, I want them next to it.”.</p>
<p>We’re still lucky because again this can be achieved using standard properties.&#160; Still in the Chart Series CustomAttributes, there’s a property named <strong>PieLabelStyle</strong>.&#160; Its default value is Inside.&#160; Switching it to Outside will render the labels outside the pie, with lines attaching them to their respective slice.</p>
<p>Other interesting properties for the outside labeling are <strong>3DLabelLineSize </strong>and <strong>MinimumRelativePieSize</strong>.</p>
<p><strong>3DLabelLineSize</strong> defines the amount of space used for drawing the line between the label and its corresponding slice and is a percentage of its default size.&#160; Values range from 30 to 200.&#160; I’ve put it to 30 to get as much space as possible for the pie itself and the labels.</p>
<p><strong>MinimumRelativePieSize </strong>represents a percentage of the chart area size and defines the minimum acceptable pie size.&#160; Values range from 10 to 70.&#160; I’ve put this one to 70 to maximize the size of the pie.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Chart Series properties with properties for outside labeling highlighted" border="0" alt="Chart Series properties with properties for outside labeling highlighted" src="http://blog.hoegaerden.be/wp-content/uploads/image93.png" width="383" height="380" /></p>
<p>With these modifications we’ve actually gotten some extra space for the labels.&#160; Let’s take advantage of that and add extra information in the labels.&#160; Change the Data Label expression to the following:</p>
<pre class="code">=<span style="color: #a31515">&quot;#LEGENDTEXT&quot; </span>&amp; vbcrlf &amp;
FormatCurrency(Sum(Fields!AnnualSales.Value) / 1000, 0) &amp; <span style="color: #a31515">&quot; (#PERCENT{P1})&quot;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<div class="code"><span style="color: #808080"></span></div>
<p>Our expression uses another built-in keyword: #LEGENDTEXT.&#160; This will add the legend text to the label itself, which means the legend becomes obsolete.&#160; So I’ve removed it.</p>
<p>And this is what our chart now looks like:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image94.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie chart showing labels on the outside" border="0" alt="Pie chart showing labels on the outside" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb15.png" width="548" height="384" /></a></p>
<p>With Halloween coming up I thought it would be nice to create a spidery chart <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h2>One More Custom Attribute</h2>
<p>I’ve already mentioned several CustomAttribute properties of the Chart Series and I’d like to mention one more.&#160; This property is called <strong>PieDrawingStyle </strong>and it will only appear in the list of properties when 3D is not enabled.&#160; After disabling 3D I could set it to either SoftEdge or Concave.&#160; I also noticed that labels outside of a pie chart will only have lines attached to them when rendered in 3D, so I’ve switched back to Inside for the PieLabelStyle property.</p>
<p>This is what SoftEdge looks like.&#160; I think it’s rather nice.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image95.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie chart using SoftEdge drawing style" border="0" alt="Pie chart using SoftEdge drawing style" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb16.png" width="477" height="518" /></a></p>
<h2>Custom Coloring</h2>
<p>To conclude, there may be some people who tell you, “I don’t like those colours, and I don’t like any of the predefined sets.&#160; I want to specify custom colours.”.</p>
<p>So again we’re lucky because even that is supported by default.</p>
<p>To get started with our color customization, select the chart object.&#160; To know if you’ve made the correct selection, the Property pane should show “Chart” as non-bold part of the dropdown.&#160; Alternatively you can just use that dropdown to select the Chart.&#160; As Chart is a main object on the report, it is shown in the list (whereas parts of a Chart, such as Chart Series and Chart Area, are not shown in that list).</p>
<p>With the Chart selected, locate the <strong>Palette </strong>property.&#160; By default it is set to BrightPastel.&#160; In case you’re happy with one of the predefined palettes you can just select it here.&#160; But we go for Custom, located at the bottom.</p>
<p>Next, locate the <strong>CustomPaletteColors </strong>property.&#160; Selecting the property will show a button with an ellipsis as button text.&#160; Click this button to get to the ReportColorExpression Collection Editor (what a name for a popup window!).&#160; This window allows you to specify a list of colors.&#160; I’ve specified the following 10 colors:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="ReportColorExpression Collection Editor" border="0" alt="ReportColorExpression Collection Editor" src="http://blog.hoegaerden.be/wp-content/uploads/image96.png" width="499" height="368" /></p>
<p>And finally this is what our report looks like.&#160; To stay in the theme, I’ve specified some colors which are suitable for Halloween-time charting.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image97.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie chart with custom colors - Halloween-style!" border="0" alt="Pie chart with custom colors - Halloween-style!" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb17.png" width="616" height="437" /></a></p>
<h3>Coloring Consistency Using Dynamic Colors</h3>
<p>And now to really conclude this article I’d like to mention one additional tip related to chart coloring.&#160; In some occasions it may be interesting to have coloring consistency between different charting periods.&#160; With that I mean that California would always show in grey, no matter whether it came first or not, Washington as brown, and so on.&#160; This is currently not the case.&#160; With the current implementation it’s the first pie that gets the grey color, the second pie is brown, and so on.</p>
<p>The best way to achieve that is to store the colors in the database and then fetch them in the same dataset that is used to retrieve the chart data.&#160; The AdventureWorks database hasn’t got any color codes stored so I’ll just illustrate what I mean using a little cheat.</p>
<p>In order to get our dynamic coloring working, we will override the colors from the palette.&#160; This is how it’s done.&#160; Right-click on the pie and select Series Properties.&#160; Select the Fill page and click the Expression (fx) button to define the color.&#160; In the case where you’re selecting the color code as one of the database fields, your expression would look similar to this (assuming that colors are stored using their 6-digit hexadecimal representation with 000000 being black and FFFFFF being white):</p>
<pre class="code">=<span style="color: #a31515">&quot;#&quot; </span>&amp; Fields!ColourCode.Value</pre>
<p>To imitate dynamic coloring I’ve used the following expression:</p>
<pre class="code">=Switch
(
    Fields!StateProvinceName.Value = <span style="color: #a31515">&quot;California&quot;</span>, <span style="color: #a31515">&quot;Blue&quot;</span>,
    Fields!StateProvinceName.Value = <span style="color: #a31515">&quot;Washington&quot;</span>, <span style="color: #a31515">&quot;Red&quot;</span>,
    Fields!StateProvinceName.Value = <span style="color: #a31515">&quot;Florida&quot;</span>, <span style="color: #a31515">&quot;Green&quot;</span>,
    <span style="color: blue">True </span>, <span style="color: #a31515">&quot;#888888&quot;
</span>)</pre>
<p>The expression gives three states their own color and all the others will be colored a kind of grey.</p>
<p>This is what it looks like:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image98.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pie Chart using dynamic colors" border="0" alt="Pie Chart using dynamic colors" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb18.png" width="569" height="401" /></a></p>
<p>So, I hope you’ve enjoyed reading this article.&#160; Feel free to post any comments should you wish to do so, and&#8230; happy charting!</p>
<h2>References</h2>
<p><a title="SQL Server 2008 Books Online: Pie Charts" href="http://msdn.microsoft.com/en-us/library/cc281303.aspx" target="_blank">SQL Server 2008 Books Online: Pie Charts</a></p>
<p><a title="How to: Collect Small Slices on a Pie Chart" href="http://msdn.microsoft.com/en-us/library/cc281305.aspx" target="_blank">How to: Collect Small Slices on a Pie Chart</a></p>
<p><a title="Formatting Data Points on a Chart" href="http://msdn.microsoft.com/en-us/library/bb677551.aspx" target="_blank">Formatting Data Points on a Chart</a></p>
<p><a title="How to: Define Colors on a Chart Using a Palette" href="http://msdn.microsoft.com/en-us/library/cc281182.aspx" target="_blank">How to: Define Colors on a Chart Using a Palette</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2009/10/25/pie-chart-techniques/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Chart Optimization Tips</title>
		<link>http://blog.hoegaerden.be/2009/07/20/chart-optimization-tips/</link>
		<comments>http://blog.hoegaerden.be/2009/07/20/chart-optimization-tips/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 13:40:37 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[Charting]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[Reporting Services 2008]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2009/07/20/chart-optimization-tips/</guid>
		<description><![CDATA[Here are some optimization techniques that can be used when creating charts in SQL Server 2008 Reporting Services.  These tips will probably be already known to experienced chart developers, but freshmen charters may spent some time searching how to achieve something before actually finding it, if finding it at all.  I know because I’ve been [...]]]></description>
			<content:encoded><![CDATA[<p>Here are some optimization techniques that can be used when creating charts in SQL Server 2008 Reporting Services.  These tips will probably be already known to experienced chart developers, but freshmen charters may spent some time searching how to achieve something before actually finding it, if finding it at all.  I know because I’ve been there myself when I started out and I also know because I’ve seen questions on forums related to this.</p>
<p>Okay, enough vague intro-words, let’s get concrete now.  In the following example I’ll be creating a regular column chart.</p>
<h2>X-axis: show all labels</h2>
<p>By default, a chart in SSRS will automatically position the labels on the X-axis as it best fits.  However, one of these options includes hiding labels when the chart feels there are too many to show.  As you can guess, this is not always what we want.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image33.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Column bar chart without any changes to its default settings" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb18.png" border="0" alt="Column bar chart without any changes to its default settings" width="496" height="283" /></a></p>
<p>Have a look at the chart above and try to guess what you’re seeing.  Difficult, huh?  Let’s make some changes to it.</p>
<p>First we start with some basics like giving it a clear title.  This chart shows the annual revenue per state/province, split up by store specialty.  The states or provinces shown are those of the selected country.  I would call it “Annual Revenue per State/Province by Specialty for &lt;SELECTED_COUNTRY&gt;”.  As you probably know, the chart’s title can be edited by giving it a single-click.  However, this does not give you the option to build an expression so unless you want to type it all from memory, here’s another option.  You can right-click on the chart’s title.  This gives you a pop-up menu with Title Properties… as one of the options.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Right-click menu on chart title" src="http://blog.hoegaerden.be/wp-content/uploads/image34.png" border="0" alt="Right-click menu on chart title" width="244" height="106" /></p>
<p>Selecting that one will give you the Chart Title Properties where you have the familiar Expression Builder icon next to Title Text textbox.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Chart Title Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image35.png" border="0" alt="Chart Title Properties" width="493" height="410" /></p>
<p>This is my expression:</p>
<div class="code"><span style="color: #0000ff;">=</span><span style="color: #808080;">&#8220;Annual Revenue per State/Province by Specialty for &#8221; </span><span style="color: #000000;">&amp;</span><span style="color: #808080;"> </span><span style="color: #000000;">Parameters!Country.Value</span></div>
<p>Also, let’s move the legend to the upper middle to make extra horizontal space for all those bars.  This can be done through the Legend Properties.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Legend Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image36.png" border="0" alt="Legend Properties" width="499" height="457" /></p>
<p>Lastly, now that we’ve freed up some space for the chart area, we’ll modify the X-axis properties so that it shows all labels.</p>
<p>When opening up the axis properties for the X-axis on a column chart you get the Category Axis Properties screen.  Like all other property screens, this is also one with several pages.  You see that one of the pages is called Labels and as you want it to show all labels, that’s were you start looking.  Well, stop looking, that’s the wrong place.  The option that you need is located in the first page, the Axis Options, and its called Interval.  This is the interval between each label on the axis, and by default it is set to Auto.  As we want all labels, change it to 1.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image37.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Category Axis Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb19.png" border="0" alt="Category Axis Properties" width="499" height="457" /></a></p>
<p>Following screenshot shows what the result looks like:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image38.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Column chart showing all labels on category axis" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb20.png" border="0" alt="Column chart showing all labels on category axis" width="496" height="281" /></a></p>
<p>Better, but we’re not quite there yet.</p>
<h2>X-axis: rotate labels in all directions</h2>
<p>Right now the labels on the X-axis are difficult to read unless we turn our screen 90 degrees clockwise.  Let’s dive again into the Category Axis Properties to put them diagonally.  On the Labels page there’s an option to specify the Label Rotation Angle.   To be able to do this you need to activate the Disable auto-fit radio button.  Putting 45 as value will give the following:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Labels rotated 45 degrees" src="http://blog.hoegaerden.be/wp-content/uploads/image39.png" border="0" alt="Labels rotated 45 degrees" width="211" height="150" /></p>
<p>The labels are rotated 45 degrees.  But not in the direction that I would prefer.  It’s nicer when they’re positioned from bottom-left to top-right.  So you start increasing the rotation value.  However, once you’re past 90 you notice that the labels stay vertically, so 135 degrees does not put them in the direction as you’d hoped.  The answer is quite simple, once you know it.  As we want the opposite of our 45 degrees, and it’s not 135, try –45 <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image40.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Category Axis Properties with Label rotation angle set to a negative value" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb21.png" border="0" alt="Category Axis Properties with Label rotation angle set to a negative value" width="494" height="453" /></a></p>
<p>Indeed, that gives the following result (I’ve also removed the X-axis title).</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image41.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Column chart with optimized X-axis" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb22.png" border="0" alt="Column chart with optimized X-axis" width="491" height="262" /></a></p>
<p>To finalize the X-axis optimization, I’ve added sorting so that the States/Provinces are sorted alphabetically.  This is a recommended design practice to keep your different charts consistent.</p>
<p>To get the labels sorted, you should not look into the Axis properties but in the Category Group Properties:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pop-up menu to get to the Category Group Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image42.png" border="0" alt="Pop-up menu to get to the Category Group Properties" width="489" height="252" /></p>
<p>On the Sorting page just add the field that’s shown on the X-axis.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image43.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Category Group Properties with sorting" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb23.png" border="0" alt="Category Group Properties with sorting" width="495" height="410" /></a></p>
<h2>Y-axis: make numbers readable</h2>
<p>So, now that we’re done with the X-axis, let’s move on to the next letter of the alphabet.  Our Y-axis (also known as Value Axis on a column chart) is not very readable at the moment.  The numbers are too large and there’s no formatting.  You don’t even see that this is a currency value.</p>
<p>This time we need the Number page of the Value Axis Properties.  We want:</p>
<ul>
<li>no decimals</li>
<li>a thousands separator</li>
<li>the numbers divided by 1000 (that’s the “Show values in” setting)</li>
<li>a dollar sign in front of the value</li>
</ul>
<p>To get all this, you can set the options as shown in the screenshot:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image44.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Value Axis Properties optimized for large currencies" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb24.png" border="0" alt="Value Axis Properties optimized for large currencies" width="485" height="444" /></a></p>
<p>And here’s our chart again:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image45.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Chart with optimized Y-axis" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb25.png" border="0" alt="Chart with optimized Y-axis" width="474" height="219" /></a></p>
<p>Additionally, the axis title has also gotten a clear value.  It indicates how the values should be read.</p>
<h2>Y-axis: move to right-hand side</h2>
<p>To conclude this article I’ll show you how to move the Y-axis to the other side of the chart.  This may seem like an odd thing to do, but sometimes the business people want to display a chart that way so you’d better have strong convincing skills or know how to do it.  Or both <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<p>In fact, a chart has got two Value axes and two Category axes, a Primary and a Secondary.  The Primary axes are the ones used right now.  To move the visible axis to the other side, it’s not through the Value Axis Properties as you might think (I think you’re getting the hang of it now, right? <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .  No, all you need to do is move all data series to the secondary axis.  This can be done through the Series Properties.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image46.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Pop-up menu on data series" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb26.png" border="0" alt="Pop-up menu on data series" width="475" height="182" /></a></p>
<p>The Axis and Chart Area page is the one you’re after.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image47.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Series Properties with Secondary Value axis activated" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb27.png" border="0" alt="Series Properties with Secondary Value axis activated" width="483" height="435" /></a></p>
<p>That will give us the following end result:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image48.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Column chart with Y-axis on the right-hand side" src="http://blog.hoegaerden.be/wp-content/uploads/image-thumb28.png" border="0" alt="Column chart with Y-axis on the right-hand side" width="470" height="233" /></a></p>
<p>BTW: you will need to re-do the axis formatting when you switch to the secondary axis so better start with axis activation before formatting it.</p>
<p>Happy charting!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2009/07/20/chart-optimization-tips/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
