<?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>Wed, 01 Feb 2012 16:15:30 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Passing A DateTime Parameter Into The Execute SQL Task</title>
		<link>http://blog.hoegaerden.be/2011/06/11/passing-a-datetime-parameter-into-the-execute-sql-task/</link>
		<comments>http://blog.hoegaerden.be/2011/06/11/passing-a-datetime-parameter-into-the-execute-sql-task/#comments</comments>
		<pubDate>Sat, 11 Jun 2011 12:31:42 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Integration Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2011/06/11/passing-a-datetime-parameter-into-the-execute-sql-task/</guid>
		<description><![CDATA[When you’ve used SSIS for a while, you may have run into the following situation already.  Or maybe today is your first time and that’s the reason that you’ve arrived here. “Huh, what’s he talking about?”, I hear you thinking.  Read on then. The Scenario You’ve got a stored procedure or another SQL statement that [...]]]></description>
			<content:encoded><![CDATA[<p>When you’ve used SSIS for a while, you may have run into the following situation already.  Or maybe today is your first time and that’s the reason that you’ve arrived here.</p>
<p><em>“Huh, what’s he talking about?”,</em> I hear you thinking.  Read on then. <img src='http://blog.hoegaerden.be/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> </p>
<h2>The Scenario</h2>
<p>You’ve got a stored procedure or another SQL statement that needs to get called from the <strong>Execute SQL Task</strong> in the Control Flow of your package.  So far so good.  One of the parameters that needs to get passed into the statement is of the <strong>DateTime</strong> type.</p>
<p>How would you do that?</p>
<h3>Parameter Mapping – Take 1</h3>
<p>Following the <a title="Wikipedia: KISS Principle" href="http://en.wikipedia.org/wiki/KISS_principle" target="_blank">KISS principle</a>, let’s say we’ve got the following really complex table in our database:</p>
<pre class="code"><span style="color: blue;">create table </span>dt <span style="color: gray;">( </span>dtVal <span style="color: blue;">datetime </span><span style="color: gray;">);</span></pre>
<p>And in our Execute SQL task we have this extremely complex INSERT statement:</p>
<pre class="code"><span style="color: blue;">insert into </span>dt <span style="color: blue;">values </span><span style="color: gray;">(</span>?<span style="color: gray;">)</span></pre>
<p>The statement is expecting one parameter.  The parameter that I want to pass into it is <em>System::StartTime</em> which is of type <strong>DateTime</strong> as shown in the screenshot below.</p>
<p><img style="display: inline; border-width: 0px;" title="Show the system variables by activating the Show System Variables button" src="http://blog.hoegaerden.be/wp-content/uploads/image416.png" border="0" alt="Show the system variables by activating the Show System Variables button" width="695" height="293" /></p>
<p><em>“Hang on, how did you get the Variables window to display the system variables?”</em></p>
<p>Ah, good question, by clicking that <strong>Show System Variables</strong> button, indicated with the red rectangle.</p>
<p>So you set up the <strong>Parameter Mapping</strong> as follows, specifying DBTIMESTAMP as Data Type and zero as Parameter Name because it’s the first parameter in the statement:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image417.png"><img style="display: inline; border-width: 0px;" title="Execute SQL Task: Parameter Mapping" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb100.png" border="0" alt="Execute SQL Task: Parameter Mapping" width="700" height="175" /></a></p>
<p>Then you decide to give it a test run.  But alas, it throws you the following error:</p>
<blockquote><p>Error: 0xC002F210 at Execute SQL Task 1, Execute SQL Task: Executing the query &#8220;insert into dt values (?)&#8221; failed with the following error: &#8220;Invalid time format&#8221;. Possible failure reasons: Problems with the query, &#8220;ResultSet&#8221; property not set correctly, parameters not set correctly, or connection not established correctly.</p></blockquote>
<p>So we’ve got a datetime column in the table and we’ve got a DateTime package variable.  But alas, the Execute SQL Task is not happy with passing this value to the query.</p>
<p>Now what?</p>
<h3>The SqlStatementSource Expression</h3>
<p>Let’s try another method then.  Instead of passing the parameter’s value through the Parameter Mapping page, we’ll set up an expression that constructs the whole INSERT statement, including the parameter’s value.</p>
<p>Have a look at the following expression:</p>
<div id="codeSnippetWrapper">
<pre id="codeSnippet" style="border-style: none; text-align: left; padding: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; width: 100%; font-family: 'Courier New',courier,monospace; direction: ltr; color: black; font-size: 8pt; overflow: visible;">
<span style="color: #006080;">"insert into dt values ('"</span> +

(DT_STR, 4, 1252) DATEPART(<span style="color: #006080;">"yyyy"</span>, @[System::StartTime]) + <span style="color: #006080;">"-"</span> +

(DT_STR, 2, 1252) DATEPART(<span style="color: #006080;">"mm"</span>, @[System::StartTime]) + <span style="color: #006080;">"-"</span> +

(DT_STR, 2, 1252) DATEPART(<span style="color: #006080;">"dd"</span>, @[System::StartTime]) + <span style="color: #006080;">" "</span> +

(DT_STR, 2, 1252) DATEPART(<span style="color: #006080;">"hh"</span>, @[System::StartTime]) + <span style="color: #006080;">":"</span> +

(DT_STR, 2, 1252) DATEPART(<span style="color: #006080;">"mi"</span>, @[System::StartTime]) + <span style="color: #006080;">":"</span> +

(DT_STR, 2, 1252) DATEPART(<span style="color: #006080;">"ss"</span>, @[System::StartTime]) + <span style="color: #006080;">"."</span> +

(DT_STR, 3, 1252) DATEPART(<span style="color: #006080;">"ms"</span>, @[System::StartTime]) + <span style="color: #006080;">"')"</span></pre>
</div>
<p>It uses the DATEPART function to fetch parts of the <em>System::StartTime</em> variable and feed it into the INSERT statement using a format that works all the time (YYYY-MM-DD HH:MM:SS.MIL).  Here’s what it generated when I clicked the <strong>Evaluate Expression</strong> button in the Expression Builder:</p>
<blockquote><p>insert into dt values (&#8217;2011-5-31 17:59:37.0&#8242;)</p></blockquote>
<p>So where exactly would you specify that expression?  In the Execute SQL Task editor, open up the <em>Expressions</em> page.  Then click the Expressions item in the Misc list so that the button with the ellipsis appears.  Now click that button, select <strong>SqlStatementSource</strong> as property and click the Ellipsis button in the Expression field to get to the Expression Builder.</p>
<p>Then you’ll end up with something like this:</p>
<p><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="The Property Expressions Editor with an expression specified for the SqlStatementSource property" src="http://blog.hoegaerden.be/wp-content/uploads/image418.png" border="0" alt="The Property Expressions Editor with an expression specified for the SqlStatementSource property" width="561" height="421" /></p>
<p>Give the package another run.  If everything has been set up as expected, the Execute SQL Task should color green and a select on the table should give one record:</p>
<p><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="Our test table contains one timestamp!" src="http://blog.hoegaerden.be/wp-content/uploads/image419.png" border="0" alt="Our test table contains one timestamp!" width="237" height="80" /></p>
<p>Hang on, does it really have to be this complicated?</p>
<p>Well, maybe not…</p>
<h3>Parameter Mapping – Take 2</h3>
<p>So let’s give the Parameter Mapping another go.</p>
<p>Set up the Execute SQL Task just like in Take 1 above, with one small difference: select DATE instead of DBTIMESTAMP as Data Type for the parameter.</p>
<p><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="Choose DATE as Data Type when passing a DateTime package variable into the Execute SQL Task" src="http://blog.hoegaerden.be/wp-content/uploads/image420.png" border="0" alt="Choose DATE as Data Type when passing a DateTime package variable into the Execute SQL Task" width="700" height="67" /></p>
<p>Now give the package another run.  Look at that, it colors green and there’s an extra record in the table:</p>
<p><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border-width: 0px;" title="An extra timestamp was written to the table" src="http://blog.hoegaerden.be/wp-content/uploads/image421.png" border="0" alt="An extra timestamp was written to the table" width="228" height="74" /></p>
<p>DATE doesn’t seem like the most logical type to choose in this scenario, which is why most people won’t even consider it.  But it works!  Actually, “DATE” is not really the best name that could be given to this particular data type.  Here’s the description of DT_DATE (not to be confused with DT_DBDATE!) <a title="Integration Services Data Types" href="http://msdn.microsoft.com/en-us/library/ms141036.aspx" target="_blank">according to MSDN</a>:</p>
<blockquote><p>A date structure that consists of year, month, day, hour, minute, seconds, and fractional seconds. The fractional seconds have a fixed scale of 7 digits.</p>
<p>The DT_DATE data type is implemented using an 8-byte floating-point number. Days are represented by whole number increments, starting with 30 December 1899, and midnight as time zero. Hour values are expressed as the absolute value of the fractional part of the number.<strong> However, a floating point value cannot represent all real values; therefore, there are limits on the range of dates that can be presented in DT_DATE.</strong></p>
<p>On the other hand, DT_DBTIMESTAMP is represented by a structure that internally has individual fields for year, month, day, hours, minutes, seconds, and milliseconds. This data type has larger limits on ranges of the dates it can present.</p></blockquote>
<p>What this means is that you have to be careful when using this type.  Even though it works fine today, it may not run fine in a similar scenario that required different date ranges.  But obviously you’ve got that covered by your unit test scenarios!</p>
<h2>Conclusion</h2>
<p>In this article I have demonstrated how a DateTime package variable can be passed as parameter into the Execute SQL Task in more than one different way.  My method of preference is the one using the DATE type in the Parameter Mapping.</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="SSIS Execute SQL Task" href="http://technet.microsoft.com/en-us/library/ms141003.aspx" target="_blank">SSIS Execute SQL Task</a></p>
<p><a title="DATEPART (SSIS Expression)" href="http://msdn.microsoft.com/en-us/library/ms137586.aspx" target="_blank">SSIS DatePart function</a></p>
<p><a title="Wikipedia: KISS Principle" href="http://en.wikipedia.org/wiki/KISS_principle" target="_blank">KISS Principle</a></p>
<p><a title="SSIS Junkie: Datetime variables don't always do what you expect" href="http://consultingblogs.emc.com/jamiethomson/archive/2005/03/12/SSIS_3A00_-Datetime-variables-don_2700_t-always-do-what-you-expect.aspx" target="_blank">SSIS Junkie: Datetime variables don&#8217;t always do what you expect</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2011%2F06%2F11%2Fpassing-a-datetime-parameter-into-the-execute-sql-task%2F&amp;title=Passing%20A%20DateTime%20Parameter%20Into%20The%20Execute%20SQL%20Task" id="wpa2a_2"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2011/06/11/passing-a-datetime-parameter-into-the-execute-sql-task/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Loading Complex XML Using SSIS</title>
		<link>http://blog.hoegaerden.be/2011/04/20/loading-complex-xml-using-ssis/</link>
		<comments>http://blog.hoegaerden.be/2011/04/20/loading-complex-xml-using-ssis/#comments</comments>
		<pubDate>Wed, 20 Apr 2011 07:31:24 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Integration Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2011/04/20/loading-complex-xml-using-ssis/</guid>
		<description><![CDATA[In my previous article I showed you how the XML Source component can be used to load XML files into a SQL Server database, using fairly simple XML structures.  In this follow-up article I will demonstrate how to tackle the complex XML issue. The Complex XML Example You probably know that SSRS reports, RDLs, are [...]]]></description>
			<content:encoded><![CDATA[<p>In <a title="Loading XML Using SSIS" href="http://blog.hoegaerden.be/2011/04/07/loading-xml-using-ssis/">my previous article</a> I showed you how the XML Source component can be used to load XML files into a SQL Server database, using fairly simple XML structures.  In this follow-up article I will demonstrate how to tackle the complex XML issue.</p>
<h2>The Complex XML Example</h2>
<p>You probably know that SSRS reports, RDLs, are actually XML files.  And they’re not the easiest types of XML files around.  To humans they are still readable but the structure can be quite complex.  So there we’ve got our example: an RDL.  More specifically I’ll be using the RDL that’s <a title="Where The Sheets Have A Name" href="http://blog.hoegaerden.be/2011/03/23/where-the-sheets-have-a-name-ssrs-excel-export/">available for download in one of my earlier articles</a>.</p>
<h3>The Goal</h3>
<p>Every good example has got a goal.  Our goal today is to retrieve a list of datasets and fields as defined in the RDL.  Shouldn’t be too difficult, right?</p>
<h3>Using The XML Source Component</h3>
<p>Let’s try to get this done through the XML Source component with which we’re very familiar by now.  You know the drill: drag an XML Source into your Data Flow, open it up and configure the XML and XSD locations.</p>
<p><strong><span style="text-decoration: underline;">Note:</span></strong> to be able to do this I cheated a bit by manually manipulating the RDL a little.  More precisely I removed all the namespace references from the &lt;report&gt; tag and further down the XML (removed “rd:”).</p>
<p>With both files configured, let’s have a look at the Columns page:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image399.png"><img style="display: inline; border: 0px;" title="The XML Source component handling a really complex XML file" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb96.png" border="0" alt="The XML Source component handling a really complex XML file" width="700" height="606" /></a></p>
<p>Look at that massive list of output flows!  In total I’ve gotten 45 of them, all for free!  Even if you’re up to the task of creating 45 output tables, do you really want to find out how to get these joined together?  To prevent creating that bunch of tables you may consider using the Merge Join component… 45 times in your data flow. Didn’t think so!</p>
<p>Sure, it would run fine if you manage to get it all constructed.  But in my opinion this is just too silly to try out because there’s an interesting alternative.</p>
<p>And that alternative is XSLT – eXtensible Stylesheet Language Transformations.</p>
<h3>Using XSLT</h3>
<p>With <strong>XSLT</strong> you describe what you want to retrieve from the XML document and what it should look like.  In this example we’ll be retrieving the list of datasets and their fields, in CSV format.  CSV stands for Comma-Separated Values, although I prefer the term “Character-Separated Values” as the separator is not always a comma.</p>
<p>To be able to write correct XSLT, you need to know what the XML structure looks like.  Here are the first 31 lines of the sample RDL file mentioned earlier.</p>
<pre class="code"><span style="color: blue;">&lt;?</span><span style="color: #a31515;">xml </span><span style="color: red;">version</span><span style="color: blue;">=</span>"<span style="color: blue;">1.0</span>" <span style="color: red;">encoding</span><span style="color: blue;">=</span>"<span style="color: blue;">utf-8</span>"<span style="color: blue;">?&gt;
&lt;</span><span style="color: #a31515;">Report</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">AutoRefresh</span><span style="color: blue;">&gt;</span>0<span style="color: blue;">&lt;/</span><span style="color: #a31515;">AutoRefresh</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">InitialPageName</span><span style="color: blue;">&gt;</span>A Very Unique Name<span style="color: blue;">&lt;/</span><span style="color: #a31515;">InitialPageName</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">DataSources</span><span style="color: blue;">&gt;
    &lt;</span><span style="color: #a31515;">DataSource </span><span style="color: red;">Name</span><span style="color: blue;">=</span>"<span style="color: blue;">srcContosoDW</span>"<span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">DataSourceReference</span><span style="color: blue;">&gt;</span>ContosoDW<span style="color: blue;">&lt;/</span><span style="color: #a31515;">DataSourceReference</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">SecurityType</span><span style="color: blue;">&gt;</span>None<span style="color: blue;">&lt;/</span><span style="color: #a31515;">SecurityType</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">DataSourceID</span><span style="color: blue;">&gt;</span>b7a3d32c-e95d-4acf-bb99-9d60755303ea<span style="color: blue;">&lt;/</span><span style="color: #a31515;">DataSourceID</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">DataSource</span><span style="color: blue;">&gt;
  &lt;/</span><span style="color: #a31515;">DataSources</span><span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">DataSets</span><span style="color: blue;">&gt;
    &lt;</span><span style="color: #a31515;">DataSet </span><span style="color: red;">Name</span><span style="color: blue;">=</span>"<span style="color: blue;">dsProductList</span>"<span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">Query</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">DataSourceName</span><span style="color: blue;">&gt;</span>srcContosoDW<span style="color: blue;">&lt;/</span><span style="color: #a31515;">DataSourceName</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">CommandText</span><span style="color: blue;">&gt;</span>select DPC.ProductCategoryName, DPS.ProductSubcategoryName, DP.ProductName
from dbo.DimProduct DP
inner join dbo.DimProductSubcategory DPS
    on DPS.ProductSubcategoryKey = DP.ProductSubcategoryKey
inner join dbo.DimProductCategory DPC
    on DPC.ProductCategoryKey = DPS.ProductCategoryKey;<span style="color: blue;">&lt;/</span><span style="color: #a31515;">CommandText</span><span style="color: blue;">&gt;
      &lt;/</span><span style="color: #a31515;">Query</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">Fields</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">Field </span><span style="color: red;">Name</span><span style="color: blue;">=</span>"<span style="color: blue;">ProductCategoryName</span>"<span style="color: blue;">&gt;
          &lt;</span><span style="color: #a31515;">DataField</span><span style="color: blue;">&gt;</span>ProductCategoryName<span style="color: blue;">&lt;/</span><span style="color: #a31515;">DataField</span><span style="color: blue;">&gt;
          &lt;</span><span style="color: #a31515;">TypeName</span><span style="color: blue;">&gt;</span>System.String<span style="color: blue;">&lt;/</span><span style="color: #a31515;">TypeName</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">Field</span><span style="color: blue;">&gt;
        &lt;</span><span style="color: #a31515;">Field </span><span style="color: red;">Name</span><span style="color: blue;">=</span>"<span style="color: blue;">ProductSubcategoryName</span>"<span style="color: blue;">&gt;
          &lt;</span><span style="color: #a31515;">DataField</span><span style="color: blue;">&gt;</span>ProductSubcategoryName<span style="color: blue;">&lt;/</span><span style="color: #a31515;">DataField</span><span style="color: blue;">&gt;
          &lt;</span><span style="color: #a31515;">TypeName</span><span style="color: blue;">&gt;</span>System.String<span style="color: blue;">&lt;/</span><span style="color: #a31515;">TypeName</span><span style="color: blue;">&gt;
        &lt;/</span><span style="color: #a31515;">Field</span><span style="color: blue;">&gt;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>As you can see, the main node is called <em>Report</em>.  Nested under <em>Report</em> we’ve got <em>DataSets</em>, which can have several <em>DataSet</em> elements.  Each <em>DataSet</em> has a set of <em>Fields</em> with one or more <em>Field</em> elements.  Using that information we come to the following XSLT.</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;">&lt;?</span><span style="color: #a31515;">xml </span><span style="color: red;">version</span><span style="color: blue;">=</span>"<span style="color: blue;">1.0</span>" <span style="color: red;">encoding</span><span style="color: blue;">=</span>"<span style="color: blue;">utf-8</span>"<span style="color: blue;">?&gt;
&lt;</span><span style="color: #a31515;">xsl:stylesheet </span><span style="color: red;">version</span><span style="color: blue;">=</span>"<span style="color: blue;">2.0</span>" <span style="color: red;">xmlns:xsl</span><span style="color: blue;">=</span>"<span style="color: blue;">http://www.w3.org/1999/XSL/Transform</span>" <span style="color: red;">xmlns:xs</span><span style="color: blue;">=</span>"<span style="color: blue;">http://www.w3.org/2001/XMLSchema</span>" <span style="color: red;">xmlns:fn</span><span style="color: blue;">=</span>"<span style="color: blue;">http://www.w3.org/2005/xpath-functions</span>"<span style="color: blue;">&gt;
  &lt;</span><span style="color: #a31515;">xsl:output </span><span style="color: red;">method</span><span style="color: blue;">=</span>"<span style="color: blue;">text</span>" <span style="color: red;">version</span><span style="color: blue;">=</span>"<span style="color: blue;">1.0</span>" <span style="color: red;">encoding</span><span style="color: blue;">=</span>"<span style="color: blue;">UTF-8</span>" <span style="color: red;">indent</span><span style="color: blue;">=</span>"<span style="color: blue;">no</span>"<span style="color: blue;">/&gt;
  &lt;</span><span style="color: #a31515;">xsl:template </span><span style="color: red;">match</span><span style="color: blue;">=</span>"<span style="color: blue;">/</span>"<span style="color: blue;">&gt;
    &lt;</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;</span>DataSource;DataSet;Field<span style="color: blue;">&lt;/</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;
    &lt;</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;</span><span style="color: red;">&amp;#13;&amp;#10;</span><span style="color: blue;">&lt;/</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;

    &lt;</span><span style="color: #a31515;">xsl:for-each </span><span style="color: red;">select</span><span style="color: blue;">=</span>"<span style="color: blue;">Report/DataSets/DataSet/Fields/Field</span>"<span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;</span>"<span style="color: blue;">&lt;/</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">xsl:value-of </span><span style="color: red;">select</span><span style="color: blue;">=</span>"<span style="color: blue;">../../Query/DataSourceName</span>"<span style="color: blue;">/&gt;
      &lt;</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;</span>";"<span style="color: blue;">&lt;/</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">xsl:value-of </span><span style="color: red;">select</span><span style="color: blue;">=</span>"<span style="color: blue;">../../@Name</span>"<span style="color: blue;">/&gt;
      &lt;</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;</span>";"<span style="color: blue;">&lt;/</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">xsl:value-of </span><span style="color: red;">select</span><span style="color: blue;">=</span>"<span style="color: blue;">@Name</span>"<span style="color: blue;">/&gt;
      &lt;</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;</span>"<span style="color: blue;">&lt;/</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;
      &lt;</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;</span><span style="color: red;">&amp;#13;&amp;#10;</span><span style="color: blue;">&lt;/</span><span style="color: #a31515;">xsl:text</span><span style="color: blue;">&gt;
    &lt;/</span><span style="color: #a31515;">xsl:for-each</span><span style="color: blue;">&gt;

  &lt;/</span><span style="color: #a31515;">xsl:template</span><span style="color: blue;">&gt;
&lt;/</span><span style="color: #a31515;">xsl:stylesheet</span><span style="color: blue;">&gt;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>So, what is the XSLT describing?  On line three, we say that the output should be text in UTF-8 encoding.  The “template match” on the fourth line takes the whole XML document into consideration, hence the forward slash.  Then on line five we start writing output through the <strong>xsl:text</strong> tag.  This is our header line.  As you can see we’re using the semi-colon as column separator in the CSV output.  Line six adds a CRLF (carriage-return + line feed) to the output.</p>
<p>Then the fun part starts.  If you have experience with XPath, the way XSLT walks through the XML document should look familiar to you.</p>
<p>The<strong> xsl:for-each</strong> tag loops over all the Fields in all the DataSets in the document.</p>
<p>Using the <strong>xsl:value-of</strong> tag, we can fetch values out of the XML.  The first value being retrieved is the name of the data source that dataset is using.  (I’ve added the retrieval of the data source to demonstrate how element values are retrieved.)  The path to the DataSourceName element is Report/DataSets/DataSet/Query/ so we use the double-dot syntax to navigate two levels up in the XML tree.  The value of the element itself is retrieved by just using its name, as demonstrated in the XSLT above.</p>
<p>The next value-of tag retrieves the Name attribute of the DataSet, hence the two levels up, and the final value-of fetches the Name attribute of the Field element.</p>
<p>Now that the XSLT is clear for everyone, how do we apply it to our XML document?  Here comes the time for SSIS once more!</p>
<p>Open up the BIDS with the Control Flow of an SSIS package active and throw in an <strong>XML Task</strong> component.</p>
<p><img style="display: inline; border: 0px;" title="The XML Task, one of the Control Flow Items in Integration Services" src="http://blog.hoegaerden.be/wp-content/uploads/image400.png" border="0" alt="The XML Task, one of the Control Flow Items in Integration Services" width="286" height="650" /></p>
<p>Double-click the component to open up the <strong>XML Task Editor</strong>.  This is what it looks like by default:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image401.png"><img style="display: inline; border: 0px;" title="XML Task Editor: default settings" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb97.png" border="0" alt="XML Task Editor: default settings" width="700" height="594" /></a></p>
<p>As this is an all-round XML task that can handle several XML-related tasks, the first setting that we need to modify is called <strong>OperationType</strong>.  That’s not too complicated because it comes with a dropdown and <em>XSLT</em> is one of the possible values.</p>
<p><img style="display: inline; border: 0px;" title="The different operation types supported by the XML Task" src="http://blog.hoegaerden.be/wp-content/uploads/image402.png" border="0" alt="The different operation types supported by the XML Task" width="517" height="163" /></p>
<p>With XSLT selected, the editor transforms into the following:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image403.png"><img style="display: inline; border: 0px;" title="The XML Task Editor with XSLT as OperationType" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb98.png" border="0" alt="The XML Task Editor with XSLT as OperationType" width="700" height="580" /></a></p>
<p>Now we need to configure where the task can find our XML file, through the <strong>Source</strong> property.  Click the Source textbox to make the dropdown appear and select &lt;New File connection…&gt;.</p>
<p><img style="display: inline; border: 0px;" title="You can create a new File Connection through the XML Task Editor" src="http://blog.hoegaerden.be/wp-content/uploads/image404.png" border="0" alt="You can create a new File Connection through the XML Task Editor" width="512" height="115" /></p>
<p>In the File Connection Manager Editor, leave the <strong>Usage type</strong> at <em>Existing file</em> and select the RDL.</p>
<p>Next up we’re going to specify where the task can find the XSLT that needs to be applied to the XML.  That can be done through the Second Operand settings.  As <strong>SecondOperandType</strong>, select <em>File Connection</em>.  Use the dropdown of the <strong>SecondOperand</strong> property to create a second new file connection that points to your XSLT file.</p>
<p>With that set up as well, only one step remains.  The task still doesn’t know where the output should be saved.  Or that it actually should get saved.  So first switch the <strong>SaveOperationResult </strong>property to True.  As you can see, <strong>DestinationType </strong>is already set to <em>File Connection</em>, that’s what we need.  Use the dropdown of the <strong>Destination</strong> property to create a third new file connection.  This time however, <strong>Usage Type </strong>should be set to <em>Create File</em>.  Specify path and filename for the output file and click OK to close the File Connection Manager Editor.</p>
<p>This is what our XML Task now looks like in the editor:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image405.png"><img style="display: inline; border: 0px;" title="The XML Task Editor with all input and output files specified, as expected for our XSLT experiment" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb99.png" border="0" alt="The XML Task Editor with all input and output files specified, as expected for our XSLT experiment" width="700" height="580" /></a></p>
<p>As shown above, I’ve called the output file DatasetInfo.csv.</p>
<p>One more property that can be interesting is the <strong>OverwriteDestination</strong> property.  Setting it to <em>True</em> can ease the testing of your package if you need to execute it multiple times.  Which you’ll probably want when your XSLT is not giving the expected output.  Don’t forget to set it to <em>False</em> afterwards (depending on what behavior you actually expect from your package).</p>
<p>Okay, now close the XML Task Editor and execute the package.  If you haven’t made any mistakes, the task should color green and you should have an extra file on your hard drive somewhere.  Here’s what the content of my DatasetInfo.csv looks like:</p>
<blockquote><p><span style="font-family: Courier New;">DataSource;DataSet;Field</p>
<p>&#8220;srcContosoDW&#8221;;&#8221;dsProductList&#8221;;&#8221;ProductCategoryName&#8221;</span></p>
<p><span style="font-family: Courier New;">&#8220;srcContosoDW&#8221;;&#8221;dsProductList&#8221;;&#8221;ProductSubcategoryName&#8221;</span></p>
<p><span style="font-family: Courier New;">&#8220;srcContosoDW&#8221;;&#8221;dsProductList&#8221;;&#8221;ProductName&#8221;</span></p>
<p><span style="font-family: Courier New;">&#8220;srcContosoDW&#8221;;&#8221;dsProductList&#8221;;&#8221;ProductCategoryColor&#8221;</span></p>
<p><span style="font-family: Courier New;">&#8220;srcContosoDW&#8221;;&#8221;dsProductList&#8221;;&#8221;EasterEgg&#8221;</span></p></blockquote>
<p>Look at that, a list of fields, all part of the dsProductList dataset.</p>
<blockquote><p>“Hang on, wasn’t this article going to demonstrate how to get complex XML files imported <strong>into our database</strong>?  And now you’re writing the data to a file?!”</p></blockquote>
<p>Well yeah, you’re right.  Unfortunately the XML Task does not offer the possibility to write to a table in a database.  So to get the data imported into your database you’ll need to set up a Data Flow that imports the CSV files.  But that shouldn’t be too difficult to achieve, right?</p>
<p>Mission accomplished!</p>
<h2>Conclusion</h2>
<p>With this article I have shown how Integration Services can be used to retrieve data out of complex XML files, without actually using the XML Source component.  I hope you’ve enjoyed reading it as much as I had while writing.  Or maybe you know another interesting method to get complex XML imported.  Feel free to post comments!</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="Wikipedia: XSLT" href="http://en.wikipedia.org/wiki/XSLT" target="_blank">XSLT (Wikipedia)</a></p>
<p><a title="Wikipedia: Comma-Separated Values" href="http://en.wikipedia.org/wiki/Comma-separated_values" target="_blank">CSV (Wikipedia)</a></p>
<p><a title="MSDN: XML Task" href="http://msdn.microsoft.com/en-us/library/ms141055.aspx" target="_blank">XML Task (MDSN)</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2011%2F04%2F20%2Floading-complex-xml-using-ssis%2F&amp;title=Loading%20Complex%20XML%20Using%20SSIS" id="wpa2a_4"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2011/04/20/loading-complex-xml-using-ssis/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Loading XML Using SSIS</title>
		<link>http://blog.hoegaerden.be/2011/04/07/loading-xml-using-ssis/</link>
		<comments>http://blog.hoegaerden.be/2011/04/07/loading-xml-using-ssis/#comments</comments>
		<pubDate>Thu, 07 Apr 2011 16:01:06 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Integration Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[SSIS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2011/04/07/loading-xml-using-ssis/</guid>
		<description><![CDATA[SQL Server Integration Services can read XML files, that’s known by every BI developer.&#160; (If you didn’t, don’t worry, I’m aiming this article at newcomers as well.) But how far can you go?&#160; When does the XML Source component become unusable?&#160; Let’s find out! To create the examples I’m using the following SQL Server version: [...]]]></description>
			<content:encoded><![CDATA[<p>SQL Server Integration Services can read XML files, that’s known by every BI developer.&#160; (If you didn’t, don’t worry, I’m aiming this article at newcomers as well.)</p>
<p>But how far can you go?&#160; When does the <strong>XML Source component </strong>become unusable?&#160; Let’s find out!</p>
<p>To create the examples I’m using the following SQL Server version:</p>
<blockquote><p>Microsoft SQL Server 2008 R2 (RTM) &#8211; 10.50.1600.1 (X64)&#160;&#160; Apr&#160; 2 2010 15:48:46&#160;&#160; Copyright (c) Microsoft Corporation&#160; Enterprise Edition (64-bit) on Windows NT 6.1 &lt;X64&gt; (Build 7600: )</p>
</blockquote>
<h2>Basic Example</h2>
<p>This first example is a really simple XML file containing a list of colors with their corresponding RGB code.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">colors</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">color </span><span style="color: red">RGB</span><span style="color: blue">=</span>&quot;<span style="color: blue">FF0000</span>&quot;<span style="color: blue">&gt;</span>Red<span style="color: blue">&lt;/</span><span style="color: #a31515">color</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">color </span><span style="color: red">RGB</span><span style="color: blue">=</span>&quot;<span style="color: blue">00FF00</span>&quot;<span style="color: blue">&gt;</span>Green<span style="color: blue">&lt;/</span><span style="color: #a31515">color</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">color </span><span style="color: red">RGB</span><span style="color: blue">=</span>&quot;<span style="color: blue">0000FF</span>&quot;<span style="color: blue">&gt;</span>Blue<span style="color: blue">&lt;/</span><span style="color: #a31515">color</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">color </span><span style="color: red">RGB</span><span style="color: blue">=</span>&quot;<span style="color: blue">FFFFFF</span>&quot;<span style="color: blue">&gt;</span>White<span style="color: blue">&lt;/</span><span style="color: #a31515">color</span><span style="color: blue">&gt;
  &lt;</span><span style="color: #a31515">color </span><span style="color: red">RGB</span><span style="color: blue">=</span>&quot;<span style="color: blue">000000</span>&quot;<span style="color: blue">&gt;</span>Black<span style="color: blue">&lt;/</span><span style="color: #a31515">color</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">colors</span><span style="color: blue">&gt;</span></pre>
<p>Let’s import this into a database.&#160; Open up the BIDS, create an SSIS project and throw a Data Flow Task into the package and open it up.</p>
<p>The component that we’re now most interested in is the <strong>XML Source</strong>, one of the components in the <em>Data Flow Sources </em>category in the Toolbox.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The XML Source component" border="0" alt="The XML Source component" src="http://blog.hoegaerden.be/wp-content/uploads/image388.png" width="295" height="181" /></p>
<p>Add one of those to your Data Flow and double-click it to open up the XML Source Editor.</p>
<p>The <strong>Data Access Mode </strong>should be set to <em>XML file location</em>, which is the default setting.&#160; The other options are <em>XML file from variable </em>– useful if you’ve got the file path and name of the XML file in a variable – and <em>XML data from variable</em> – interesting if your XML data is actually stored in a variable.</p>
<p>As <strong>XML Location</strong>, select the .xml file.&#160; Our XML sample does not have an inline schema, so we can’t use that checkbox.&#160; And we can’t click the OK button either, it’s grayed out.&#160; The source component really expects a description of the XML structure before the editor can be closed.</p>
<p>The bottom of the screen even shows a warning with the following message:</p>
<blockquote>
<p>XML Schema (XSD) is not specified. Select an existing XSD or click Generate XSD to create an XSD from the XML file.</p>
</blockquote>
<p>So, what are you waiting for,&#160; Click the <strong>Generate XSD </strong>button to let the XML Source Editor generate the XSD schema for us.&#160; Real easy, right?</p>
<p>Remember where you save the file, and when it’s generated, select the .xsd file in the <strong>XSD location</strong> textbox.&#160; As you can see, the OK button will become available.&#160; But don’t click it just yet.</p>
<p>Here’s what the XML Source Editor now looks like:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image389.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="XML Source Editor with an XML and XSD file specified" border="0" alt="XML Source Editor with an XML and XSD file specified" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb90.png" width="700" height="607" /></a></p>
<p>Let’s now move on to the second page of the XML Source Editor, called Columns.&#160; When you open it, you’ll receive the following popup with a couple of warnings:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image390.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Warning gets displayed when opening the Columns page" border="0" alt="Warning gets displayed when opening the Columns page" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb91.png" width="700" height="306" /></a></p>
<p>The editor is letting us know that the columns that are being generated do not have a maximum length specified.&#160; So it’s setting them to Unicode (DT_WSTR) with a length of 255.&#160; Click the OK button to get rid of that message and to be able to see the generated columns.</p>
<p><strong>Note:</strong> if your data elements or attributes may contain longer strings then you should have a look at modifying the length specification.&#160; This can be done through the Advanced Editor, which is opened by right-clicking the XML Source.&#160; The Input and Output Properties page is the one you’re after.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The Columns page, showing the columns that the XML Source generated for us" border="0" alt="The Columns page, showing the columns that the XML Source generated for us" src="http://blog.hoegaerden.be/wp-content/uploads/image391.png" width="700" height="607" /></p>
<p>As you can see, our only attribute – RGB, is nicely put in a column with the same name.&#160; The value of each &lt;color&gt; node however is not put in a column called Color.&#160; By default, this value is put into a column called “text”.&#160; Which is a weird name for a column in an SSIS data flow if you ask me.&#160; The good thing is that you can just rename it by changing the <strong>Output Column</strong> value.</p>
<p>Let’s test this out.&#160; My favorite way is to add a <strong>Multicast </strong>component to the Data Flow, then add a Data Viewer on the connector (right-click the green arrow, select Data Viewers, click Add &gt; OK &gt; OK).&#160; Now execute the package to get this result:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Testing the output of the XML Source through the Data Viewer" border="0" alt="Testing the output of the XML Source through the Data Viewer" src="http://blog.hoegaerden.be/wp-content/uploads/image392.png" width="545" height="261" /></p>
<p>Mission accomplished, we’ve retrieved data from a very basic XML file!</p>
<h2>Adding Some Complexity</h2>
<p>Let’s move on to the second example of this article.&#160; The difference with the previous example is that now we’ve got multiple nested structures to deal with.</p>
<p>The example represents a list of book reviews, including some details on the books themselves.&#160; A book can have multiple writers and obviously multiple reviews as well.</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">books</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">book </span><span style="color: red">pages</span><span style="color: blue">=</span>&quot;<span style="color: blue">300</span>&quot;<span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">title</span><span style="color: blue">&gt;</span>Microsoft SQL Server 2008 R2 Master Data Services<span style="color: blue">&lt;/</span><span style="color: #a31515">title</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">category</span><span style="color: blue">&gt;</span>Information Technology<span style="color: blue">&lt;/</span><span style="color: #a31515">category</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">authors</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>Jeremy Kashel<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>Tim Kent<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>Martyn Bullerwell<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">authors</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">reviews</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">review</span><span style="color: blue">&gt;</span>If you're looking for an excellent book on the new Master Data Services component of SQL Server 2008 R2, definitely check this one out!  To be released in June 2011 by Packt Publishing!<span style="color: blue">&lt;/</span><span style="color: #a31515">review</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">reviews</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">book</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">book </span><span style="color: red">pages</span><span style="color: blue">=</span>&quot;<span style="color: blue">832</span>&quot;<span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">title</span><span style="color: blue">&gt;</span>Inside Microsoft SQL Server 2008: T-SQL Querying<span style="color: blue">&lt;/</span><span style="color: #a31515">title</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">category</span><span style="color: blue">&gt;</span>Information Technology<span style="color: blue">&lt;/</span><span style="color: #a31515">category</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">authors</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>Itzik Ben-gan<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>Lubor Kollar<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>Dejan Sarka<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
      &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>Steve Kass<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">authors</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">reviews</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">review</span><span style="color: blue">&gt;</span>Every &quot;Inside SQL Server&quot; book can be recommended, especially when written by Itzik!<span style="color: blue">&lt;/</span><span style="color: #a31515">review</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">reviews</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">book</span><span style="color: blue">&gt;
    &lt;</span><span style="color: #a31515">book </span><span style="color: red">pages</span><span style="color: blue">=</span>&quot;<span style="color: blue">1137</span>&quot;<span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">title</span><span style="color: blue">&gt;</span>The Lord of the Rings<span style="color: blue">&lt;/</span><span style="color: #a31515">title</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">category</span><span style="color: blue">&gt;</span>Fantasy<span style="color: blue">&lt;/</span><span style="color: #a31515">category</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">authors</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">author</span><span style="color: blue">&gt;</span>J.R.R. Tolkien<span style="color: blue">&lt;/</span><span style="color: #a31515">author</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">authors</span><span style="color: blue">&gt;
        &lt;</span><span style="color: #a31515">reviews</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">review</span><span style="color: blue">&gt;</span>Like fantasy?  What are you waiting for then?  It's a classic!<span style="color: blue">&lt;/</span><span style="color: #a31515">review</span><span style="color: blue">&gt;
            &lt;</span><span style="color: #a31515">review</span><span style="color: blue">&gt;</span>If you liked the movie, you'll love the book.<span style="color: blue">&lt;/</span><span style="color: #a31515">review</span><span style="color: blue">&gt;
        &lt;/</span><span style="color: #a31515">reviews</span><span style="color: blue">&gt;
    &lt;/</span><span style="color: #a31515">book</span><span style="color: blue">&gt;
&lt;/</span><span style="color: #a31515">books</span><span style="color: blue">&gt;</span></pre>
<p>Configure an <strong>XML Source</strong> so that it uses the books.xml file, generate the XSD and specify its location.&#160; I’m not going into details on that, the procedure is the same as in our first example above.</p>
<p>Now open up the <strong>Columns</strong> page to have a closer look at how the XML data is going to get imported.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image397.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="XML Source generates multiple outputs" border="0" alt="XML Source generates multiple outputs" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb94.png" width="700" height="603" /></a></p>
<p>So how does the XML Source component deal with the multiple nested structures?&#160; It generates multiple outputs!&#160; If you select another output from that dropdown, you get to see its fields.</p>
<p>To get a clear understanding of what exactly is going on, let’s connect each output with an <strong>OLE DB Destination </strong>component.&#160; The target table can be generated based on the incoming fields by clicking the <strong>New</strong> button.&#160; Replace the table name in the generated CREATE TABLE script with a clear one that fulfills your naming convention requirements – such as NO SPACES IN A TABLE NAME for instance – and hit the OK button.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image394.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Destinatio table can be generated by using the New button in the OLE DB Destination Editor" border="0" alt="Destinatio table can be generated by using the New button in the OLE DB Destination Editor" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb93.png" width="700" height="607" /></a></p>
<p>Now that the table is created, it will be automatically selected in the <strong>Name of the table or the view </strong>dropdown.&#160; Don’t forget to visit the Mappings page so that the, well, mappings are created.&#160; If no field names were modified in the CREATE TABLE script then all fields should be mapped automatically based on their names.</p>
<p>With all five destinations added, execute 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="Each XML Source output is connected to an OLE DB Destination - executes fine" border="0" alt="Each XML Source output is connected to an OLE DB Destination - executes fine" src="http://blog.hoegaerden.be/wp-content/uploads/image395.png" width="615" height="391" /></p>
<p>So now we’ve loaded the data from our XML file into a database, but the data is spread over five tables.&#160; How do we retrieve that data?&#160; Join them together!</p>
<pre class="code"><span style="color: blue">select </span><span style="color: gray">* </span><span style="color: blue">from </span>XML_book
<span style="color: gray">inner join </span>XML_authors <span style="color: blue">on </span>XML_authors<span style="color: gray">.</span>book_Id <span style="color: gray">= </span>XML_book<span style="color: gray">.</span>book_Id
<span style="color: gray">inner join </span>XML_author <span style="color: blue">on </span>XML_author<span style="color: gray">.</span>authors_Id <span style="color: gray">= </span>XML_authors<span style="color: gray">.</span>authors_Id
<span style="color: gray">inner join </span>XML_reviews <span style="color: blue">on </span>XML_reviews<span style="color: gray">.</span>book_Id <span style="color: gray">= </span>XML_book<span style="color: gray">.</span>book_Id
<span style="color: gray">inner join </span>XML_review <span style="color: blue">on </span>XML_review<span style="color: gray">.</span>reviews_Id <span style="color: gray">= </span>XML_reviews<span style="color: gray">.</span>reviews_Id<span style="color: gray">;</span></pre>
<p>And the result looks like this:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image398.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="XML data imported into the SQL Server database" border="0" alt="XML data imported into the SQL Server database" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb95.png" width="700" height="113" /></a></p>
<h2>Conclusion</h2>
<p>We have managed to flatten the data from an XML file containing multiple nested repeating nodes, nice huh?&#160; But do you also feel the limitation using this method?&#160; In terms of modern XML, this was still a fairly easy XML file and yet we already needed five tables to store the data.&#160; Can you imagine what this will give with a really complex file?</p>
<p>Watch this blog for <a title="Loading Complex XML Using SSIS" href="http://blog.hoegaerden.be/2011/04/20/loading-complex-xml-using-ssis/">the follow-up article</a> where I will try to import data from a really complex XML file!</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="XML Source component" href="http://msdn.microsoft.com/en-us/library/ms140277.aspx" target="_blank">XML Source component</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2011%2F04%2F07%2Floading-xml-using-ssis%2F&amp;title=Loading%20XML%20Using%20SSIS" id="wpa2a_6"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2011/04/07/loading-xml-using-ssis/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Where The Sheets Have A Name</title>
		<link>http://blog.hoegaerden.be/2011/03/23/where-the-sheets-have-a-name-ssrs-excel-export/</link>
		<comments>http://blog.hoegaerden.be/2011/03/23/where-the-sheets-have-a-name-ssrs-excel-export/#comments</comments>
		<pubDate>Wed, 23 Mar 2011 18:38:50 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[Reporting Services 2008 R2]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2011/03/23/where-the-sheets-have-a-name-ssrs-excel-export/</guid>
		<description><![CDATA[Did you know that as of SQL Server Reporting Services 2008 R2 you can give the worksheets a customized name when exporting your report to Excel?  If you didn’t, or you did but never took the time to find out how you’d implement that, I’ll show you here and now! For this example I’ll be [...]]]></description>
			<content:encoded><![CDATA[<p>Did you know that as of <strong>SQL Server Reporting Services 2008 R2</strong> you can give the worksheets a customized name when exporting your report to Excel?  If you didn’t, or you did but never took the time to find out how you’d implement that, I’ll show you here and now!</p>
<p>For this example I’ll be starting off from the report created in <a title="Cascading Calculated Fields (SSRS)" href="http://blog.hoegaerden.be/2011/03/07/cascading-calculated-fields-ssrs/">my earlier post on Cascading Calculated Fields</a>.</p>
<p>The result can be <a title="NamingExcelSheets.rdl" href="http://cid-81c8b064cbbe1698.office.live.com/self.aspx/.Public/blog/NamingExcelSheets.rdl" target="_blank">downloaded from my Skydrive through this link</a>.</p>
<h2>The Scenario</h2>
<p>As you may recall, our report shows a list of all our company’s products.  When the report gets exported to Excel, each product category should get its own sheet.  So all products from the Audio category should be located in a sheet called “Audio”, all Games and Toys in a sheet called “Games and Toys”, and so on.</p>
<h2>The Report</h2>
<h3>Starting Position</h3>
<p>Let’s first have a quick look what the export to Excel currently looks like, without any modifications to the report.</p>
<p><img style="display: inline; border-width: 0px;" title="Default export to Excel - all data in one sheet" src="http://blog.hoegaerden.be/wp-content/uploads/image379.png" border="0" alt="Default export to Excel - all data in one sheet" width="700" height="639" /></p>
<p>All records are being exported to just one sheet.  And, by default, the name of the sheet is the name of the report.  (I made a copy of my existing report and called it NamingExcelSheets.rdl.)</p>
<p>In case you want to change the default name of the sheet, it’s possible.  On the report itself, there’s a property called <strong>InitialPageName</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Use the InitialPageName property on the report to change the default name of the Excel sheet" src="http://blog.hoegaerden.be/wp-content/uploads/image380.png" border="0" alt="Use the InitialPageName property on the report to change the default name of the Excel sheet" width="428" height="437" /></p>
<p>Fill in a value and here’s the result in Excel:</p>
<p><img style="display: inline; border-width: 0px;" title="The Excel sheet with its default name changed to a very unique name" src="http://blog.hoegaerden.be/wp-content/uploads/image381.png" border="0" alt="The Excel sheet with its default name changed to a very unique name" width="667" height="457" /></p>
<h3>Adding The Category Group</h3>
<p>To be able to get the different categories into different sheets, we need to add a group on Category to the tablix in the report.</p>
<p>With the tablix selected, right-click the <em>Details </em>line in the <em>Row Groups </em>pane and select <strong>Add Group &gt; Parent Group</strong>.  Select ProductCategoryName as field to group by and activate the <strong>Add group header</strong> checkbox.</p>
<p><img style="display: inline; border-width: 0px;" title="Add group on Product Category" src="http://blog.hoegaerden.be/wp-content/uploads/image382.png" border="0" alt="Add group on Product Category" width="682" height="320" /></p>
<p>Remove the group column that gets added automatically and move the header cells from the main header to the group header.  Delete the main header row so that you end up with something like this:</p>
<p><img style="display: inline; border-width: 0px;" title="Tablix with group on Product Category added" src="http://blog.hoegaerden.be/wp-content/uploads/image383.png" border="0" alt="Tablix with group on Product Category added" width="580" height="93" /></p>
<p>Open up the <strong>Group Properties </strong>by double-clicking the new ProductCategoryName item in the <em>Row Groups </em>pane.  Select the <em>Page Breaks </em>page and activate the <strong>Between each instance of a group </strong>checkbox.  Doing this ensures that each group gets its own page in the report, and its own sheet in Excel.</p>
<p><img style="display: inline; border-width: 0px;" title="Adding page breaks between the instances of a group" src="http://blog.hoegaerden.be/wp-content/uploads/image384.png" border="0" alt="Adding page breaks between the instances of a group" width="585" height="482" /></p>
<p>Let’s render the report and export to Excel to have a look at the effect of adding these page breaks.</p>
<p><img style="display: inline; border-width: 0px;" title="Report exported to Excel with each group in a separate sheet" src="http://blog.hoegaerden.be/wp-content/uploads/image385.png" border="0" alt="Report exported to Excel with each group in a separate sheet" width="661" height="398" /></p>
<p>Indeed, every group has gotten its own worksheet.  However, they’ve also gotten the very original names such as Sheet1, Sheet2 and so on.</p>
<h3>Customizing The Names Of The Sheets</h3>
<p>On to the final part of the requirements: giving our own customized name to the generated Excel sheets.  This is actually really easy once you know how to do this.</p>
<p>First select the ProductCategoryName group in the Row Groups pane so that its properties are displayed in the Properties pane.  In the Properties pane, locate the Group &gt; PageName property and specify the following expression:</p>
<pre class="code">=Fields!ProductCategoryName.Value</pre>
<p>That’s it, that’s all you need to do!  Don’t believe me?  Here’s what the export to Excel now looks like:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image386.png"><img style="display: inline; border-width: 0px;" title="Data exported to Excel, with customized sheetnames" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb89.png" border="0" alt="Data exported to Excel, with customized sheetnames" width="700" height="347" /></a></p>
<h2>Conclusion</h2>
<p>As we’ve seen in this article, it really doesn’t take too much effort to implement a custom name for the worksheets when exporting a report to Excel.  Neat feature!</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="Understanding Pagination in Reporting Services (Report Builder 3.0 and SSRS)" href="http://msdn.microsoft.com/en-us/library/dd255278.aspx" target="_blank">Understanding Pagination in Reporting Services (Report Builder 3.0 and SSRS)</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2011%2F03%2F23%2Fwhere-the-sheets-have-a-name-ssrs-excel-export%2F&amp;title=Where%20The%20Sheets%20Have%20A%20Name" id="wpa2a_8"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2011/03/23/where-the-sheets-have-a-name-ssrs-excel-export/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Cascading Calculated Fields (SSRS)</title>
		<link>http://blog.hoegaerden.be/2011/03/07/cascading-calculated-fields-ssrs/</link>
		<comments>http://blog.hoegaerden.be/2011/03/07/cascading-calculated-fields-ssrs/#comments</comments>
		<pubDate>Mon, 07 Mar 2011 18:21:07 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2011/03/07/cascading-calculated-fields-ssrs/</guid>
		<description><![CDATA[When thinking about Reporting Services in combination with the word cascading, the first that jumps to mind is cascading parameters.  We all know that one parameter can have its list of values filtered by what’s selected in another parameter. But what about calculated fields?  Are those cascading as well?  Can we refer to a calculated [...]]]></description>
			<content:encoded><![CDATA[<p>When thinking about Reporting Services in combination with the word cascading, the first that jumps to mind is cascading parameters.  We all know that one parameter can have its list of values filtered by what’s selected in another parameter.</p>
<p>But what about calculated fields?  Are those cascading as well?  Can we refer to a calculated field in the definition of another calculated field?  Let’s find out!</p>
<p>For the example I’ll be using the ContosoDW sample data warehouse running on SQL Server 2008 R2, more precisely:</p>
<blockquote><p>Microsoft SQL Server 2008 R2 (RTM) &#8211; 10.50.1600.1 (X64)   Apr  2 2010 15:48:46   Copyright (c) Microsoft Corporation  Enterprise Edition (64-bit) on Windows NT 6.1 &lt;X64&gt; (Build 7600: )</p></blockquote>
<p>The result can be <a title="CascadingCalculatedFields.rdl" href="http://cid-81c8b064cbbe1698.office.live.com/self.aspx/.Public/blog/CascadingCalculatedFields.rdl" target="_blank">downloaded from my Skydrive through this link</a>.</p>
<h2>The Example</h2>
<h3>Scenario</h3>
<p>We’ve been asked to build a report that produces a product catalogue.  The report only has one requirement: as our company is well-known for its branding, each product category has got its own color and this color should be used as background color in the report.</p>
<h3>Report</h3>
<p>Let’s first get some data.  Here’s a fairly simple query that retrieves all products with their related category and subcategory from the ContosoDW database:</p>
<pre class="code"><span style="color: blue;">select </span>DPC<span style="color: gray;">.</span>ProductCategoryName<span style="color: gray;">, </span>DPS<span style="color: gray;">.</span>ProductSubcategoryName<span style="color: gray;">, </span>DP<span style="color: gray;">.</span>ProductName
<span style="color: blue;">from </span>dbo<span style="color: gray;">.</span>DimProduct DP
<span style="color: gray;">inner join </span>dbo<span style="color: gray;">.</span>DimProductSubcategory DPS
    <span style="color: blue;">on </span>DPS<span style="color: gray;">.</span>ProductSubcategoryKey <span style="color: gray;">= </span>DP<span style="color: gray;">.</span>ProductSubcategoryKey
<span style="color: gray;">inner join </span>dbo<span style="color: gray;">.</span>DimProductCategory DPC
    <span style="color: blue;">on </span>DPC<span style="color: gray;">.</span>ProductCategoryKey <span style="color: gray;">= </span>DPS<span style="color: gray;">.</span>ProductCategoryKey<span style="color: gray;">;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>After building a dataset in a new report I end up with this:</p>
<p><img style="display: inline; border-width: 0px;" title="The Report Data pane before adding any calculated fields" src="http://blog.hoegaerden.be/wp-content/uploads/image374.png" border="0" alt="The Report Data pane before adding any calculated fields" width="245" height="233" /></p>
<h4>Calculated Field Number One</h4>
<p>Because this post is about calculated fields, we’re now going to apply a little dirty trick of hard-coding the category names and their corresponding color into a calculated field.  I do not recommend this for professional reports where the colors should be coming from the database so that your reports are not impacted when extra categories are added or when the marketing department decides to change their vision.</p>
<p>But for this example it’s perfect so let’s create a calculated field in the dataset.  That can be done by right-clicking the dataset and then selecting <strong>Add Calculated Field…</strong></p>
<p><img style="display: inline; border-width: 0px;" title="Right-click the dataset to add a calculated field" src="http://blog.hoegaerden.be/wp-content/uploads/image375.png" border="0" alt="Right-click the dataset to add a calculated field" width="325" height="170" /></p>
<p>Give the field a clear name, such as ProductCategoryColor, and click the fx button to enter the following expression:</p>
<pre class="code">=Switch(
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"Audio"</span>, <span style="color: #a31515;">"#FFD800"</span>,
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"Cameras and camcorders "</span>, <span style="color: #a31515;">"#FF0000"</span>,
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"Cell phones"</span>, <span style="color: #a31515;">"#00FF00"</span>,
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"Computers"</span>, <span style="color: #a31515;">"#0000FF"</span>,
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"Games and Toys"</span>, <span style="color: #a31515;">"#FF00FF"</span>,
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"Home Appliances"</span>, <span style="color: #a31515;">"#FFFF00"</span>,
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"Music, Movies and Audio Books"</span>, <span style="color: #a31515;">"#00FFFF"</span>,
    Fields!ProductCategoryName.Value = <span style="color: #a31515;">"TV and Video"</span>, <span style="color: #a31515;">"#ABCD12"
</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p><em>Funny side note: do you notice that trailing space in the “Cameras and Camcorders” category?  It’s intentional!  Apparently that record has got a trailing space stored in the ProductCategoryName field in DimProductCategory.</em></p>
<p>With the first calculated field created, add a table to your report to display the products.  Set the <strong>BackgroundColor </strong>property of the whole Details row to the newly-created calculated field.</p>
<p>So far so good, here’s what the rendered report currently looks like:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image376.png"><img style="display: inline; border-width: 0px;" title="Rendered report with background color" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb87.png" border="0" alt="Rendered report with background color" width="700" height="195" /></a></p>
<h4>Calculated Field Number Two</h4>
<p>According to the business requirements we’re done creating the report.  However, it’s Friday early afternoon and we feel like having some fun.  And this post is about “cascading” calculated fields, so we need at least two of them.  Let’s create an Easter egg!</p>
<p>The “fun” requirement is the following: if the product’s name starts with an A then the text color for that record should be the same as the background color, but with the Blue component set to FF.  For example, if the background color is #00FF00 (green) then the text color should become #00FFFF (cyan).</p>
<p>Let’s create another calculated field in our dataset, called EasterEgg (don’t make it too hard for your colleagues to fix the weirdly behaving report).  Give it the following expression:</p>
<pre class="code">=IIF(Left(Fields!ProductName.Value, 1) = <span style="color: #a31515;">"A"</span>,
    Left(Fields!ProductCategoryColor.Value, 5) + <span style="color: #a31515;">"FF"</span>,
    <span style="color: #a31515;">"Black"</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>As you can see, we’re referring to the ProductCategoryColor field, the calculated field created earlier.</p>
<p>Now set the <strong>Color</strong> property of the Details row to this new calculated field and Preview the report.</p>
<p>Guess what?</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image377.png"><img style="display: inline; border-width: 0px;" title="Rendered report with cascading calculated field" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb88.png" border="0" alt="Rendered report with cascading calculated field" width="700" height="199" /></a></p>
<p>It works!</p>
<h2>Conclusion</h2>
<p>If you’re in a situation where you’d like to add calculated fields to an existing dataset and one of those fields should use the value of another calculated field, you can do it!  Cascading calculated fields are working fine in Reporting Services.</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2011%2F03%2F07%2Fcascading-calculated-fields-ssrs%2F&amp;title=Cascading%20Calculated%20Fields%20%28SSRS%29" id="wpa2a_10"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2011/03/07/cascading-calculated-fields-ssrs/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Finding Similar Strings With Fuzzy Logic Functions Built Into MDS</title>
		<link>http://blog.hoegaerden.be/2011/02/05/finding-similar-strings-with-fuzzy-logic-functions-built-into-mds/</link>
		<comments>http://blog.hoegaerden.be/2011/02/05/finding-similar-strings-with-fuzzy-logic-functions-built-into-mds/#comments</comments>
		<pubDate>Sat, 05 Feb 2011 13:58:30 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Master Data Services]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[MDS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2011/02/05/finding-similar-strings-with-fuzzy-logic-functions-built-into-mds/</guid>
		<description><![CDATA[This post is inspired by a presentation that’s available on the Microsoft TechEd Online website.  It’s called Master Data Management – Merging from Multiple Sources, and is presented by Dejan Sarka, one of the Solid Quality Mentors and writer of several SQL Server-related books. Even if you’re not interested in Master Data Services (MDS), the [...]]]></description>
			<content:encoded><![CDATA[<p>This post is inspired by a presentation that’s available on the <a title="Microsoft TechEd Online" href="http://www.msteched.com/" target="_blank">Microsoft TechEd Online website</a>.  It’s called <a title="Master Data Management – Merging from Multiple=" target="_blank">Master Data Management – Merging from Multiple Sources</a>, and is presented by <strong>Dejan Sarka</strong>, one of the Solid Quality Mentors and writer of several SQL Server-related books.</p>
<p>Even if you’re not interested in Master Data Services (MDS), the following will be good to know if you need to compare strings with each other for similarity and find the string that’s the closest match to your input string.</p>
<h2>Compare Strings Why?</h2>
<p>You may be wondering in what scenarios you’d be required to compare strings for similarity.  To clarify, I’ll give you an example.  Imagine you’re building a data warehouse (DWH).  This DWH receives data from several different source systems.  In two of those systems, you’ve got a list of customers.  To be able to populate your DimCustomer table and avoid duplicate customers, you need to implement some logic to detect that customer Smith in System A is the same customer Smith in System B.</p>
<p>That’s when string similarity or fuzzy-logic functions come in handy.</p>
<h2>Compare Strings How?</h2>
<p>When strings are 100% equal, it’s obviously not difficult to find matching strings.  Just use the equals (=) operator in your query and you’ve matched them.  However, when strings are not 100% equal, due to typing errors or whatever cause, things get a little more complicated.  Perhaps customer Smith in System A is called Smyth, Smiht or even Smiths in System B while they are actually one and the same person.  That’s when we need to use additional logic, which we – not being rock star mathematicians ourselves – can hopefully find in built-in system functions.</p>
<h3>The Built-in Soundex() And Difference() Functions</h3>
<p>The standard functionality available in SQL Server to compare strings is fairly limited.  You’ve probably heard of the SOUNDEX() function, maybe even used in somehow already.  This function receives a string as parameter and calculates a four-digit code out of it.  When used on two similar strings, the two strings will produce the same code.  When they are not similar, you get two different codes.  And that’s it.</p>
<p>Here’s an example:</p>
<pre class="code"><span style="color: blue;">select </span><span style="color: magenta;">SOUNDEX</span><span style="color: gray;">(</span><span style="color: red;">'Smith'</span><span style="color: gray;">), </span><span style="color: magenta;">SOUNDEX</span><span style="color: gray;">(</span><span style="color: red;">'Smiht'</span><span style="color: gray;">), </span><span style="color: magenta;">SOUNDEX</span><span style="color: gray;">(</span><span style="color: red;">'Washington'</span><span style="color: gray;">)</span></pre>
<p><a href="http://11011.net/software/vspaste"></a>The result of that query is:</p>
<p><img style="display: inline; border: 0px;" title="Result of SOUNDEX query" src="http://blog.hoegaerden.be/wp-content/uploads/image368.png" border="0" alt="Result of SOUNDEX query" width="347" height="41" /></p>
<p>Is it perfect?  No, it’s not.  If you’d give it a value of ‘Smiths’, it would return S532, which is different from S530 even though there’s only one letter of difference between the two strings.</p>
<p>Next to SOUNDEX() we’ve got the DIFFERENCE() function.  This function accepts two parameters and returns an integer between 0 and 4.  What this function does is it calculates the soundex value for both strings and returns the number of characters of the code that are matching.  In the case of a comparison of ‘Smith’ with ‘Smiths’, it would return 3 because three characters are matching (‘S53’).</p>
<p>Let’s move on to an alternative solution.</p>
<h3>The Similarity Function In Master Data Services</h3>
<p>The MDS installation procedure goes through several steps to get all the required functionality installed.  One of those steps is the creation of a database.  What’s interesting about this database, even if you’re not interested in MDS or Master Data Management, are the custom functions that it contains.</p>
<p>One of those functions is called <strong>Similarity</strong>, located in the <strong>mdq</strong> schema.  This function allows you to compare two strings with each other through a specified match algorithm.  What’s interesting here is that you can choose between those four different algorithms depending on your data.  In some cases a certain algorithm will be more interesting while in other cases the best algorithm will be another one.</p>
<p>The value returned by the Similarity function is a float between zero and one, which makes it more precise than the soundex option.</p>
<p>So how do you use the function?  Let’s have a look at its definition:</p>
<pre class="code"><span style="color: blue;">ALTER FUNCTION </span>[mdq]<span style="color: gray;">.</span>[Similarity]<span style="color: gray;">(</span>@input1 [nvarchar]<span style="color: gray;">(</span>4000<span style="color: gray;">), </span>@input2 [nvarchar]<span style="color: gray;">(</span>4000<span style="color: gray;">),</span>

  @method [tinyint]<span style="color: gray;">, </span>@containmentBias [float]<span style="color: gray;">, </span>@minScoreHint [float]<span style="color: gray;">)
</span><span style="color: blue;">RETURNS </span>[float] <span style="color: blue;">WITH EXECUTE AS CALLER</span><span style="color: gray;">, </span><span style="color: blue;">RETURNS </span><span style="color: gray;">NULL </span><span style="color: blue;">ON </span><span style="color: gray;">NULL </span>INPUT
<span style="color: blue;">AS
EXTERNAL </span>NAME [Microsoft.MasterDataServices.DataQuality]<span style="color: gray;">.</span>

<span style="color: gray;"> </span>  [Microsoft.MasterDataServices.DataQuality.SqlClr]<span style="color: gray;">.</span>[Similarity]</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>As you can see, this is not a standard T-SQL function but it’s been implemented in .NET through CLR Integration.  The function expects five parameters.  The first two parameters, @input1 and @input2, are the two strings that need to get compared.  The third parameter specifies the match algorithm that should be used.</p>
<p>Here are the four algorithms as supported by the Similarity function:</p>
<table border="1" cellspacing="0" cellpadding="2" width="499">
<tbody>
<tr>
<td width="198" valign="top"><strong>Value for @method</strong></td>
<td width="299" valign="top"><strong>Algorithm</strong></td>
</tr>
<tr>
<td width="198" valign="top">0</td>
<td width="299" valign="top">The Levenshtein edit distance algorithm</td>
</tr>
<tr>
<td width="198" valign="top">1</td>
<td width="299" valign="top">The Jaccard similarity coefficient algorithm</td>
</tr>
<tr>
<td width="198" valign="top">2</td>
<td width="299" valign="top">A form of the Jaro-Winkler distance algorithm</td>
</tr>
<tr>
<td width="198" valign="top">3</td>
<td width="299" valign="top">Longest common subsequence algorithm</td>
</tr>
</tbody>
</table>
<p>The fourth parameter, @containmentBias, specifies how exact the fuzzy index should be when comparing strings of different lengths.  Values go from 0.0 to 1.0 with the lower number being the more precise one.  This only applies to the Jaccard and longest common subsequence algorithms.  The default is 0.85.</p>
<p>The fifth parameter, @minScoreHint, influences the calculated scores returned by the Similarity function.  Valid values go from 0.0 to 1.0.  When a value greater than 0 is passed, any calculated score under that value will result in zero.</p>
<p><strong><span style="text-decoration: underline;">Note:</span></strong> according to the Books Online, this fifth parameter is optional.  But it’s not.</p>
<p><strong><span style="text-decoration: underline;">Note:</span></strong> also according to the Books Online, a value of 4 for @method would also be accepted.   In that case the function will use a date comparison algorithm, thus the two first parameters should be either DateTime values or valid dates that are strings specified in the format<em> yyyy-mm-dd</em>.  However, when testing this out I noticed that this is not working.  Further exploration of the MDS database led me to another function called <strong>SimilarityDate</strong>, also located in the <strong>mdq</strong> schema:</p>
<pre class="code"><span style="color: blue;">ALTER FUNCTION </span>[mdq]<span style="color: gray;">.</span>[SimilarityDate]<span style="color: gray;">(</span>@date1 [datetime]<span style="color: gray;">, </span>@date2 [datetime]<span style="color: gray;">)
</span><span style="color: blue;">RETURNS </span>[float] <span style="color: blue;">WITH EXECUTE AS CALLER</span><span style="color: gray;">, </span><span style="color: blue;">RETURNS </span><span style="color: gray;">NULL </span><span style="color: blue;">ON </span><span style="color: gray;">NULL </span>INPUT
<span style="color: blue;">AS
EXTERNAL </span>NAME [Microsoft.MasterDataServices.DataQuality]<span style="color: gray;">.</span>

<span style="color: gray;">  </span>[Microsoft.MasterDataServices.DataQuality.SqlClr]<span style="color: gray;">.</span>[SimilarityDate]</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>From the looks of it, this function implements the functionality as explained in the BOL for @method = 4.  And this one is actually working!</p>
<p>So how do you find out which of the four algorithms is the most interesting one in your situation?  You’ll have to try it out.  Take a sample data set and run the four algorithms on the data.  As I don’t have any real-world data to use here (it wouldn’t be legal anyway), I’ll demonstrate this using some data from the ContosoDW database.</p>
<p>The following query uses the Customer dimension and combines that with a very small set of “sample” data that imitate some real-world problems like typos.</p>
<pre class="code"><span style="color: blue;">with </span>DistinctLastname <span style="color: blue;">as
</span><span style="color: gray;">(
    </span><span style="color: blue;">select distinct </span>LastName
    <span style="color: blue;">from </span>DimCustomer
<span style="color: gray;">),
</span>NewData <span style="color: blue;">as
</span><span style="color: gray;">(
    </span><span style="color: blue;">select </span><span style="color: red;">'Wahsington' </span><span style="color: blue;">as </span>LastName2 <span style="color: green;">--typo
    </span><span style="color: blue;">union select </span><span style="color: red;">'Wqshington' </span><span style="color: green;">--QWERTY/AZERTY mixup
    </span><span style="color: blue;">union select </span><span style="color: red;">'Zqtson' </span><span style="color: green;">--QWERTY/AZERTY mixup x2
</span><span style="color: gray;">)
</span><span style="color: blue;">select </span>DistinctLastname<span style="color: gray;">.</span>LastName<span style="color: gray;">, </span>NewData<span style="color: gray;">.</span>LastName2
<span style="color: blue;">into </span>#SampleData
<span style="color: blue;">from </span>DistinctLastname
<span style="color: gray;">cross join </span>NewData
<span style="color: blue;">where </span>LastName <span style="color: gray;">is not null;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>I’m only using the LastName column here.  In a real situation you’d probably want to combine that with FirstName and also some address-related data such as city and street.</p>
<p>Up next is letting the algorithms loose on the data set:</p>
<pre class="code"><span style="color: blue;">select </span>LastName<span style="color: gray;">, </span>LastName2<span style="color: gray;">,
    </span>MDS<span style="color: gray;">.</span>mdq<span style="color: gray;">.</span>Similarity<span style="color: gray;">(</span>LastName<span style="color: gray;">, </span>LastName2<span style="color: gray;">, </span>0<span style="color: gray;">, </span>0.85<span style="color: gray;">, </span>0<span style="color: gray;">) </span><span style="color: blue;">as </span>Levenshtein<span style="color: gray;">,
    </span>MDS<span style="color: gray;">.</span>mdq<span style="color: gray;">.</span>Similarity<span style="color: gray;">(</span>LastName<span style="color: gray;">, </span>LastName2<span style="color: gray;">, </span>1<span style="color: gray;">, </span>0.85<span style="color: gray;">, </span>0<span style="color: gray;">) </span><span style="color: blue;">as </span>Jaccard<span style="color: gray;">,
    </span>MDS<span style="color: gray;">.</span>mdq<span style="color: gray;">.</span>Similarity<span style="color: gray;">(</span>LastName<span style="color: gray;">, </span>LastName2<span style="color: gray;">, </span>2<span style="color: gray;">, </span>0.85<span style="color: gray;">, </span>0<span style="color: gray;">) </span><span style="color: blue;">as </span>JaroWinkler<span style="color: gray;">,
    </span>MDS<span style="color: gray;">.</span>mdq<span style="color: gray;">.</span>Similarity<span style="color: gray;">(</span>LastName<span style="color: gray;">, </span>LastName2<span style="color: gray;">, </span>3<span style="color: gray;">, </span>0.85<span style="color: gray;">, </span>0<span style="color: gray;">) </span><span style="color: blue;">as </span>LongestCommonSubsequence
<span style="color: blue;">from </span>#SampleData<span style="color: gray;">;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Copy the results of that query to Excel for further, and easier, analysis.  You can easily sort your data in Excel, so that the highest calculated scores of a certain algorithm are located on top.</p>
<p>Let’s first start by sorting on the <strong>Levenshtein</strong> results:</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image369.png"><img style="display: inline; border: 0px;" title="Results ordered on Levenshtein value" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb84.png" border="0" alt="Results ordered on Levenshtein value" width="700" height="123" /></a></p>
<p>As you can see, the three values that we were looking for are located on top.  That’s a good sign!  Furthermore, the Washington values are quite high.  So based on my sample data this is possibly a good algorithm.</p>
<p>How about the <strong>Jaccard</strong> results?</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image370.png"><img style="display: inline; border: 0px;" title="Results for the Jaccard algorithm" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb85.png" border="0" alt="Results for the Jaccard algorithm" width="700" height="175" /></a></p>
<p>You can clearly see that the maximum values for the Jaccard algorithm are significantly lower than those of the other algorithms.  Furthermore, the correct value for Watson is scoring lower than Son.  Assuming our logic would select the best-scoring values when searching for “Watson”, it would select the incorrect value of Son.</p>
<p>All this indicates that the Jaccard algorithm is not the best-suited one for our situation.</p>
<p>So, what about <strong>Jaro-Winkler</strong>?</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image371.png"><img style="display: inline; border: 0px;" title="Results for the Jaro-Winkler algorithm" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb86.png" border="0" alt="Results for the Jaro-Winkler algorithm" width="700" height="176" /></a></p>
<p>In this case we’ve got even higher maximum values compared to Levenshtein and the two values for Washington are located on top.  So far so good.  The correct value for Watson is located at position 7.  But as you can see, this is the first match for Zqtson, which means that the correct value would get selected by our matching logic.  Based on these numbers I would say that so far this is the best algorithm for the situation.</p>
<p>One more to go: <strong>Longest Common Subsequence</strong>.</p>
<p><img style="display: inline; border: 0px;" title="Results for the Longest Common Subsequence algorithm" src="http://blog.hoegaerden.be/wp-content/uploads/image372.png" border="0" alt="Results for the Longest Common Subsequence algorithm" width="700" height="116" /></p>
<p>Again the three correct values are located on top, just like the Levenshtein algorithm.  In fact, the calculated scores are very similar to the Levenshtein algorithm.  Quite logical: both calculations are using similar algorithms.</p>
<h2>Conclusion</h2>
<p>Based on the results above and using this very limited sample data set, I would select the Jaro-Winkler algorithm as being the most suitable for our situation.  But I do have to mention that you should really use larger data sets to be sure.</p>
<p>Also, even though we can rely on a fuzzy-logic algorithm to find the correct match, the selected matches should be verified and approved manually.  Of course, all that can be part of a Master Data Management process.</p>
<p>Note that for this post I only looked at fuzzy matching possibilities using just T-SQL.  In Integration Services there are a couple of components, such as the Fuzzy Lookup data flow component, that offer similar functionality.  If you’re dealing with ETL flows in SSIS, be sure to check that one out as well!</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="ContosoDW sample database" href="http://www.microsoft.com/downloads/en/details.aspx?FamilyID=868662DC-187A-4A85-B611-B7DF7DC909FC&amp;amp%3Bdisplaylang=en" target="_blank">Microsoft Contoso BI Demo Dataset for Retail Industry</a></p>
<p><a title="Fuzzy String Searching" href="http://en.wikipedia.org/wiki/Fuzzy_string_searching" target="_blank">Fuzzy String Searching</a></p>
<p><a title="Soundex" href="http://en.wikipedia.org/wiki/Soundex" target="_blank">Soundex algorithm</a></p>
<p><a title="Levenshtein distance" href="http://en.wikipedia.org/wiki/Levenshtein_distance" target="_blank">Levenshtein Distance</a></p>
<p><a title="Jaccard index" href="http://en.wikipedia.org/wiki/Jaccard_index" target="_blank">Jaccard Index</a></p>
<p><a title="Jaro–Winkler distance" href="http://en.wikipedia.org/wiki/Jaro%E2%80%93Winkler_distance" target="_blank">Jaro-Winkler Distance</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2011%2F02%2F05%2Ffinding-similar-strings-with-fuzzy-logic-functions-built-into-mds%2F&amp;title=Finding%20Similar%20Strings%20With%20Fuzzy%20Logic%20Functions%20Built%20Into%20MDS" id="wpa2a_12"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2011/02/05/finding-similar-strings-with-fuzzy-logic-functions-built-into-mds/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Hide/Show Items Dependant On Export Format (SSRS)</title>
		<link>http://blog.hoegaerden.be/2011/01/18/ssrs-hideshow-items-dependant-on-export-format/</link>
		<comments>http://blog.hoegaerden.be/2011/01/18/ssrs-hideshow-items-dependant-on-export-format/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 18:00:02 +0000</pubDate>
		<dc:creator>Valentino Vranken</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQLServerPedia Syndication]]></category>
		<category><![CDATA[data]]></category>
		<category><![CDATA[SQL Server 2008 R2]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://blog.hoegaerden.be/2011/01/18/ssrs-hideshow-items-dependant-on-export-format/</guid>
		<description><![CDATA[Now and then I encounter forum questions in the style of the following: I have a report with a title.  When rendered through the Report Manager and when exported to PDF, I want it to render as normal.  However, when exported to Excel I do not want to get the title.  How can I hide [...]]]></description>
			<content:encoded><![CDATA[<p>Now and then I encounter forum questions in the style of the following:</p>
<blockquote><p>I have a report with a title.  When rendered through the Report Manager and when exported to PDF, I want it to render as normal.  However, when exported to Excel I do not want to get the title.  How can I hide it?</p></blockquote>
<p>Because I don’t like re-inventing the wheel each time I decided to write a blog post about it.</p>
<p>As of SQL Server 2008 R2, we’ve got a built-in global field that can help us out.  This field is called <strong>Globals!RenderFormat</strong>.  It has two properties: <strong>Name</strong> and <strong>IsInteractive</strong>.  Name represents the unique name that indicates the chosen renderer, and IsInteractive indicates whether or not the chosen report format is, well, interactive.</p>
<p>Depending on the renderer, the values of the properties differ.  To be able to use the variable in an expression, we need to know its values for each rendering format.  Here’s the list of different possibilities:</p>
<table border="1" cellspacing="0" cellpadding="2" width="682">
<tbody>
<tr>
<td width="363" valign="top"><strong>Renderer</strong></td>
<td width="133" valign="top"><strong>RenderFormat.Name</strong></td>
<td width="184" valign="top"><strong>RenderFormat.IsInteractive</strong></td>
</tr>
<tr>
<td width="363" valign="top">Preview in BIDS or rendered through Report Manager</td>
<td width="133" valign="top">RPL</td>
<td width="184" valign="top">True</td>
</tr>
<tr>
<td width="363" valign="top">XML file with report data</td>
<td width="133" valign="top">XML</td>
<td width="184" valign="top">False</td>
</tr>
<tr>
<td width="363" valign="top">CSV (comma delimited)</td>
<td width="133" valign="top">CSV</td>
<td width="184" valign="top">False</td>
</tr>
<tr>
<td width="363" valign="top">TIFF file or Print button</td>
<td width="133" valign="top">IMAGE</td>
<td width="184" valign="top">False</td>
</tr>
<tr>
<td width="363" valign="top">PDF</td>
<td width="133" valign="top">PDF</td>
<td width="184" valign="top">False</td>
</tr>
<tr>
<td width="363" valign="top">MHTML (web archive)</td>
<td width="133" valign="top">MHTML</td>
<td width="184" valign="top">True</td>
</tr>
<tr>
<td width="363" valign="top">Excel</td>
<td width="133" valign="top">EXCEL</td>
<td width="184" valign="top">False</td>
</tr>
<tr>
<td width="363" valign="top">Word</td>
<td width="133" valign="top">WORD</td>
<td width="184" valign="top">False</td>
</tr>
</tbody>
</table>
<p>If these names for RenderFormat look familiar to you, you’re probably right.  Have a look at the <em>rsreportserver.config</em> file in the <em>C:\Program Files\Microsoft SQL Server\MSRS10_50.SQL2008R2\Reporting Services\ReportServer</em> folder.  Note that you may need to adapt the folder to your specific settings.  In my case my instance is called “SQL2008R2”.  Near the bottom of that configuration file you can find the <em>&lt;Render&gt; </em>node, located under <em>&lt;Extensions&gt;</em>.  The names that you see there are those used by the RenderFormat.Name property.</p>
<p>Now that we know what values to test on, let’s get started.</p>
<p>If we get back to the example of hiding a title, or textbox, when exporting to Excel, here’s what needs to happen.  Locate the <strong>Hidden</strong> property of the textbox that you want to hide, and give it the following expression:</p>
<pre class="code">=IIF(Globals!RenderFormat.Name = <span style="color: #a31515;">"EXCEL"</span>, <span style="color: blue;">True</span>, <span style="color: blue;">False</span>)</pre>
<p><a href="http://11011.net/software/vspaste"></a>What we’re saying here is: if the RenderFormat is EXCEL, then the Hidden property should be set to True.  Which results in a hidden textbox whenever the report is exported to Excel!</p>
<p><em>As Erik pointed out in the comments, in this particular case you don&#8217;t need the IIF() statement.  The result of the expression results in True when the expected value should be True, and False when False is expected.</em></p>
<p>As a quick note: when building your expression through the expression builder, you’ll notice that the Intellisense doesn’t know the new RenderFormat field yet.  Do not worry about that, just continue typing and ignore any errors being indicated.  If you use the syntax as I highlighted above, it will work!  Well, unless you’re running an earlier version than SQL Server 2008 R2 of course.  In that case it won’t work.</p>
<p><img style="display: inline; border: 0px;" title="Intellisense doesn't know RenderFormat yet" src="http://blog.hoegaerden.be/wp-content/uploads/image366.png" border="0" alt="Intellisense doesn't know RenderFormat yet" width="265" height="211" /></p>
<p>In contradiction to the Intellisense, the bottom part of the expression builder screen has been updated to show the new properties.  So if you don’t remember the syntax, you can just locate the field in the <em>Built-in Fields</em> category and give it a good double-click.</p>
<p><a href="http://blog.hoegaerden.be/wp-content/uploads/image367.png"><img style="display: inline; border: 0px;" title="RenderFormat is located in the Built-in Fields category" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb83.png" border="0" alt="RenderFormat is located in the Built-in Fields category" width="700" height="193" /></a></p>
<p>Of course, the Excel example in this post is just one of many possibilities that this new field offers.  Is your company environment-friendly and does it want to prevent wasting paper?  Now it’s possible, just hide that 50-pages long table when the report is being rendered for print!</p>
<p>Have fun!</p>
<p>Valentino.</p>
<p><strong>References</strong></p>
<p><a title="Globals!RenderFormat aka Renderer Dependent Report Layout" href="http://blogs.msdn.com/b/robertbruckner/archive/2010/05/02/globals-renderformat-aka-renderer-dependent-report-layout.aspx" target="_blank">Globals!RenderFormat aka Renderer Dependent Report Layout by Robert Bruckner</a></p>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2011%2F01%2F18%2Fssrs-hideshow-items-dependant-on-export-format%2F&amp;title=Hide%2FShow%20Items%20Dependant%20On%20Export%20Format%20%28SSRS%29" id="wpa2a_14"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></a></p>]]></content:encoded>
			<wfw:commentRss>http://blog.hoegaerden.be/2011/01/18/ssrs-hideshow-items-dependant-on-export-format/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<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.  Instead of re-inventing the wheel each time, I decided to write an article about the subject.  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 [...]]]></description>
			<content:encoded><![CDATA[<p>On the forums I now and then encounter questions regarding images on SSRS reports.  Instead of re-inventing the wheel each time, I decided to write an article about the subject.  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.  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.  This catalogue should contain all products produced by our two daughter companies: The Canyon Peak and Great Falls Soft.  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>
<li>
<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.  The logo should be displayed in the company’s header.</li>
<li>Each product has a logo.  The logo should be displayed as part of the product details.</li>
</ol>
</li>
</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></p>
<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.  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.  I’ve added some comments to make it clear what the query is doing.  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="display: inline; border-width: 0px;" title="Results of the query" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb71.png" border="0" alt="Results of the query" 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.  Looking at the scenario requirements described earlier, this is requirement 1.</p>
<p>Let’s add a header to the report.  In the BIDS menu, select <strong>Report</strong> &gt; <strong>Add Page Header</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Adding a header to a report" src="http://blog.hoegaerden.be/wp-content/uploads/image304.png" border="0" alt="Adding a header to a report" width="265" height="178" /></p>
<p>If you don’t see the Report menu item, you probably have not selected your report.  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.  Doing that will show a pop-up window, the Image Properties.  By default, the <strong>Select the image source </strong>combobox is set to <em>Embedded</em>.  Good, that’s what we need at this point.  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.  Our marketing department has given me two images for use in the header: Cloudy_banner.png and AnotherCloudy_banner.png.  Let’s select the first one.</p>
<p><img style="display: inline; border-width: 0px;" title="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" border="0" alt="Adding an image to a report by using the Import button on the Image Properties window" 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.  By default this is set to JPEG files.</p>
<p>Here’s the result in the Image Properties:</p>
<p><img style="display: inline; border-width: 0px;" title="Image Properties with an image selected" src="http://blog.hoegaerden.be/wp-content/uploads/image306.png" border="0" alt="Image Properties with an image selected" width="585" height="532" /></p>
<p>On the Size page, select <em>Clip</em> instead of <em>Fit proportional</em>.  This is a setting that you’ll need to look at case per case.  For our header images, <em>Clip</em> is the most suitable option.</p>
<p><img style="display: inline; border-width: 0px;" title="Image Properties: set Display to Clip" src="http://blog.hoegaerden.be/wp-content/uploads/image307.png" border="0" alt="Image Properties: set Display to Clip" 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="display: inline; border-width: 0px;" title="Image added to report header" src="http://blog.hoegaerden.be/wp-content/uploads/image308.png" border="0" alt="Image added to report header" width="544" height="180" /></p>
<p>As you can see, we now have an image in the header.  But we haven’t fully implemented the requirement yet.  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.  In the Report Data pane, locate the <em>Images</em> node and open it up.  You’ll notice that the image that we inserted earlier can be found here.</p>
<p><img style="display: inline; border-width: 0px;" title="The Images node in the Report Data pane shows all embedded images" src="http://blog.hoegaerden.be/wp-content/uploads/image309.png" border="0" alt="The Images node in the Report Data pane shows all embedded images" width="168" height="159" /></p>
<p>Right-click the <em>Images</em> node and select <strong>Add Image</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Right-click Images node to add an embedded image to the report" src="http://blog.hoegaerden.be/wp-content/uploads/image310.png" border="0" alt="Right-click Images node to add an embedded image to the report" width="229" height="155" /></p>
<p>That opens up the familiar file Open dialog which was used to add the first image.  So I’m now selecting the file called AnotherCloudy_banner.png, after changing the default filter to PNG.  After clicking OK, the image gets added under the Images node.</p>
<p><img style="display: inline; border-width: 0px;" title="Second banner image added to the report" src="http://blog.hoegaerden.be/wp-content/uploads/image311.png" border="0" alt="Second banner image added to the report" width="190" height="64" /></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>.  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.  These are the same values as displayed in the Report Data pane.  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;">"Cloudy_banner"</span>, <span style="color: #a31515;">"AnotherCloudy_banner"</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.  When page number can be divided by two, which means it’s an even page number, Cloudy_banner is displayed.  Otherwise the other banner is displayed.</p>
<p>That’s it, the report header is finished.  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.  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>"<span style="color: blue;">Cloudy_banner</span>"<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.  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.  Select <strong>Add Group &gt; Parent Group</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Right-click the Details line in Row Groups to add a new parent group" src="http://blog.hoegaerden.be/wp-content/uploads/image312.png" border="0" alt="Right-click the Details line in Row Groups to add a new parent group" width="646" height="160" /></p>
<p>Group by Company and add a group header:</p>
<p><img style="display: inline; border-width: 0px;" title="Tablix grouping" src="http://blog.hoegaerden.be/wp-content/uploads/image313.png" border="0" alt="Tablix grouping" width="451" height="201" /></p>
<p>Remove the extra first column that just got generated:</p>
<p><img style="display: inline; border-width: 0px;" title="Remove unwanted column" src="http://blog.hoegaerden.be/wp-content/uploads/image314.png" border="0" alt="Remove unwanted column" width="646" height="189" /></p>
<p>We’ve now got an empty tablix with two columns, a Details row and a Company header row.  In our dataset, one of the fields is called <em>CompanyDescription</em>.  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="display: inline; border-width: 0px;" title="Click the small icon to get a list of fields" src="http://blog.hoegaerden.be/wp-content/uploads/image315.png" border="0" alt="Click the small icon to get a list of fields" 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.  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;">"file:C:\vavr\test\" </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.  In my example the files are located in a local folder called c:\vavr\test.  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="display: inline; border-width: 0px;" title="The Image Properties configured to display an External image" src="http://blog.hoegaerden.be/wp-content/uploads/image316.png" border="0" alt="The Image Properties configured to display an External image" width="417" height="200" /></p>
<p>By default the image gets displayed using the <em>Fit Proportional </em>setting.  You can verify this in the <strong>Size</strong> page of the Image Properties.  We want the image to get fully displayed while maintaining the aspect ratio, so leave the setting as it is.  Close the image properties dialog.</p>
<p>Vertically enlarge the first row in our tablix to an acceptable size.  In my case the marketing department specified to use a height of 1.5 inches for the company logo.  With the image selected, locate the Size &gt; Height property and set it to “1,5in”.  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="display: inline; border-width: 0px;" title="The report with company logos added" src="http://blog.hoegaerden.be/wp-content/uploads/image317.png" border="0" alt="The report with company logos added" 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.  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.  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.  To get full control over layout I want to make the detail part of the tablix a freestyle part.  First merge the two cells together by selecting both of them, then right-click and choose <strong>Merge Cells</strong>.</p>
<p><img style="display: inline; border-width: 0px;" title="Merging two cells together in a tablix" src="http://blog.hoegaerden.be/wp-content/uploads/image318.png" border="0" alt="Merging two cells together in a tablix" width="686" height="632" /></p>
<p>Now select a <strong>Rectangle</strong> in the Toolbox pane and drop it into the merged area.  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.  I’m also adding some additional labels and fields, as shown in the next screenshot.</p>
<p><img style="display: inline; border-width: 0px;" title="The product details in Design view" src="http://blog.hoegaerden.be/wp-content/uploads/image319.png" border="0" alt="The product details in Design view" width="347" height="196" /></p>
<p>As you can see I’ve modified the fonts a bit.  The rendered version:</p>
<p><img style="display: inline; border-width: 0px;" title="The rendered product details" src="http://blog.hoegaerden.be/wp-content/uploads/image320.png" border="0" alt="The rendered product details" 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;">"unknown"</span>,
    Fields!Weight.Value &amp; <span style="color: #a31515;">" " </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;">" " </span>&amp; Fields!SizeUnitMeasureCode.Value</pre>
<p>For the layout of 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.  (You did keep some space available, right?)</p>
<p>Again we get the familiar Image Properties popup.  Give it a good name, like ProductImage, and select the image source that we haven’t used yet, <em>Database</em>.  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.  You can verify this by running a select on the Production.ProductPhoto table.  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.  That one is called Tooltip.  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="display: inline; border-width: 0px;" title="The final report, with a tooltip on the product image" src="http://blog.hoegaerden.be/wp-content/uploads/image321.png" border="0" alt="The final report, with a tooltip on the product image" 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>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2010%2F07%2F07%2Fput-some-images-on-those-ssrs-reports%2F&amp;title=Put%20Some%20Images%20On%20Those%20SSRS%20Reports" id="wpa2a_16"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></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>5</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 [...]]]></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>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2010%2F06%2F01%2Faggregating-data-with-the-over-clause%2F&amp;title=Aggregating%20Data%20With%20The%20OVER%20Clause" id="wpa2a_18"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></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.&#160; Today I’m going to show you another new feature of SSRS 2008 R2, this time in the visualization department.&#160; This feature is the Data Bar.&#160; 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.&#160; Today I’m going to show you another new feature of SSRS 2008 R2, this time in the visualization department.&#160; 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>.&#160; With this new component it’s fairly easy to make your tabular data a lot more visual, and thus easier to interpret.&#160; 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>.&#160; That allows me to focus on the visualization part, without first needing to build a table report.&#160; (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.&#160; We’re going to add an extra column on the right of the table to contain the data bar.&#160; Let’s first explore the Toolbox pane to discover the new visualization report items.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The new Reporting Services 2008 R2 report items: Map, Data Bar, Sparkline and Indicator" border="0" alt="The new Reporting Services 2008 R2 report items: Map, Data Bar, Sparkline and Indicator" src="http://blog.hoegaerden.be/wp-content/uploads/image262.png" width="120" height="342" /></p>
<p>The new items have been highlighted in yellow.&#160; As you can see, besides <strong>Data Bar </strong>there’s also <strong>Sparkline, </strong><strong>Map </strong>and <strong>Indicator</strong>.&#160; 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.&#160; Doing that will show the following popup window:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Select Data Bar Type window" border="0" alt="Select Data Bar Type window" src="http://blog.hoegaerden.be/wp-content/uploads/image263.png" width="348" height="482" /></p>
<p>From left to right, there’s Bar, Stacked Bar and 100% Stacked Bar.&#160; And those are also available in vertical direction, Column.&#160; 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.&#160; We first need to tell it what data to visualize.&#160; Clicking it once will select it, clicking it once more will show us the following <strong>Chart Data </strong>popup:</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Data Bar: Chart Data" border="0" alt="Data Bar: Chart Data" src="http://blog.hoegaerden.be/wp-content/uploads/image264.png" width="612" height="434" /></p>
<p>Click the plus icon to get a drop-down of fields in the dataset.&#160; 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/image350.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Data Bar: Chart Data with Reseller_Sales_Amount selected" border="0" alt="Data Bar: Chart Data with Reseller_Sales_Amount selected" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb81.png" width="700" height="385" /></a>&#160;</p>
<p>By default, the aggregation used on the data is Sum.&#160; But there are other options as well, have a look at the dropdown next to the [Sum(Reseller_Sales…&#160; In the example here I’m going to keep the Sum.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Other aggregation functions of the Data Bar" border="0" alt="Other aggregation functions of the Data Bar" src="http://blog.hoegaerden.be/wp-content/uploads/image266.png" 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report preview with the data bar" border="0" alt="Report preview with the data bar" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb63.png" 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.&#160; 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.&#160; Setting up the color of the Data Bar is done as follows: select the Data Bar so that you get the Chart Data popup.&#160; In the Properties pane you should see that the Chart Series is selected.&#160; Then right-click on the bar and select <strong>Series Properties</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The right-click menu on the Data Bar." border="0" alt="The right-click menu on the Data Bar." src="http://blog.hoegaerden.be/wp-content/uploads/image268.png" width="434" height="445" /></p>
<p>In the <strong>Series Properties</strong> window, select the <strong>Fill</strong> page and select your favorite color.&#160; If you want you can also use a gradient fill or pattern.&#160; 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.&#160; Well, in short, any expression that you can think of and results in a color will work fine!</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Series Properies: setting up the Fill color" border="0" alt="Series Properies: setting up the Fill color" src="http://blog.hoegaerden.be/wp-content/uploads/image269.png" 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report with data bar on two grouping levels" border="0" alt="Report with data bar on two grouping levels" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb64.png" 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.&#160; An even nicer example is United Kingdom with only one state England.&#160; 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.&#160; Canada and United Kingdom are in the Country group and all Country data bars compare nicely to each other.&#160; 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.&#160; 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>”.&#160; 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>”.&#160; 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.&#160; So, right-click one of the data bars in the new column and select <strong>Horizontal Axis Properties</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 menu on tablix textbox with a data bar" border="0" alt="Right-click menu on tablix textbox with a data bar" src="http://blog.hoegaerden.be/wp-content/uploads/image271.png" width="545" height="568" /></p>
<p>As you can see, the default for the <em>Maximum</em> value is set to “<em>Auto</em>”.&#160; Note that the name of my tablix is “Tablix1”, as shown in the <em>Align axes in</em> dropdown.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Horizontal Axis Properties" border="0" alt="Horizontal Axis Properties" src="http://blog.hoegaerden.be/wp-content/uploads/image272.png" 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">&quot;Tablix1&quot;</span>)</pre>
<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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Report rendered with status bar scoped over whole dataset" border="0" alt="Report rendered with status bar scoped over whole dataset" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb65.png" 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.&#160; 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.&#160; 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">&quot;grpCountry&quot;</span>)</pre>
<p>The grpCountry refers to the name of the grouping one level higher, 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="The groupings as defined on my example tablix" border="0" alt="The groupings as defined on my example tablix" src="http://blog.hoegaerden.be/wp-content/uploads/image274.png" 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">&quot;Tablix1&quot;</span>)</pre>
<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.&#160; Right-click the Data Bar (after first selecting the textbox that contains it) and choose <strong>Show Data Labels</strong>.</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Show Data Labels in right-click popup on Chart Series" border="0" alt="Show Data Labels in right-click popup on Chart Series" src="http://blog.hoegaerden.be/wp-content/uploads/image275.png" width="309" height="300" /></p>
<p>That adds a label to the chart but we still need to configure it to show the percentage.&#160; By default it uses the value as label.&#160; This can be verified in the <strong>Chart Series </strong>properties:</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: UseValueAsLabel" border="0" alt="Chart Series properties: UseValueAsLabel" src="http://blog.hoegaerden.be/wp-content/uploads/image276.png" width="287" height="392" /></p>
<p>The <strong>UseValueAsLabel</strong> is set to <em>True</em>, confirming what I just stated.&#160; Furthermore, activating the <strong>Show Data Labels </strong>option also set the <strong>Visible</strong> property to <em>True</em>.&#160; 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.&#160; Right-click it and select <strong>Series Label Properties</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 menu on label" border="0" alt="Right-click menu on label" src="http://blog.hoegaerden.be/wp-content/uploads/image277.png" width="275" height="179" /></p>
<p>The General page of the <strong>Series Label Properties </strong>window allows you to define the Label data.&#160; 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Do you want to set the UseValueAsLabel to False?" border="0" alt="Do you want to set the UseValueAsLabel to False?" src="http://blog.hoegaerden.be/wp-content/uploads/image278.png" 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Data Bar with Label selected" border="0" alt="Data Bar with Label selected" src="http://blog.hoegaerden.be/wp-content/uploads/image279.png" 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.&#160; This actually makes it easier because we can use the same expression on both the State/Province and Country level.&#160; 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Preview of report with labels on data bars" border="0" alt="Preview of report with labels on data bars" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb66.png" width="700" height="185" /></a></p>
<p>Woah, looks like we forgot something doesn’t it?&#160; We forgot to format the label as being a percentage!&#160; 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Series Label Properties: formatting number as percentage" border="0" alt="Series Label Properties: formatting number as percentage" src="http://blog.hoegaerden.be/wp-content/uploads/image281.png" 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Chart Series Labels properties" border="0" alt="Chart Series Labels properties" src="http://blog.hoegaerden.be/wp-content/uploads/image282.png" 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="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="The final report with two data bar columns" border="0" alt="The final report with two data bar columns" src="http://blog.hoegaerden.be/wp-content/uploads/image_thumb67.png" width="700" height="201" /></a></p>
<p>That sure looks better doesn’t it?&#160; The status bars on the right compare over the grouping levels while those on the left compare with each other within the same group.&#160; And they all have a clear label indicating what they represent.</p>
<p>And then colleague-expert <a title="mark_wills @ EE" href="http://www.experts-exchange.com/M_4390378.html" target="_blank">Mark Wills</a> jumps in with the following remark (rephrased a little):</p>
<blockquote>
<p>Hang on, are you really sure those bars on the left are what they should be?&#160; How&#8217;s it possible then that 71% of NSW (Australia) appears to be only about 20% and the 100% of England (United Kingdom) is only halfway filled?</p>
</blockquote>
<p>Interesting observation and indeed, Mark is right: those data bars on the left are still not right!&#160; Let’s get this fixed.</p>
<p>On the Country level the fix is really easy.&#160; What we want the bar to reflect here is the same as in the bar on the right: the percentage of the country compared to the whole dataset.&#160; That’s achieved using this expression as <em>Maximum</em> in the <strong>Horizontal Axis Properties</strong>:</p>
<pre class="code">=Sum(Fields!Reseller_Sales_Amount.Value, <span style="color: #a31515">&quot;Tablix1&quot;</span>)</pre>
<p>Here’s what that looks like:</p>
<p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="Data bar on Country level now reflects the percentage of the group" border="0" alt="Data bar on Country level now reflects the percentage of the group" src="http://blog.hoegaerden.be/wp-content/uploads/image446.png" width="700" height="110" /></p>
<p>And finally, here’s the expression to be used to fix the data bar on State/Province level:</p>
<pre class="code">=Sum(Fields!Reseller_Sales_Amount.Value, <span style="color: #a31515">&quot;grpCountry&quot;</span>)</pre>
<p>Indeed, the data bar on this level should show the percentage compared to all the items in the group.</p>
<p>Final result:</p>
<p><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="All data bars fully operational as advertised!" border="0" alt="All data bars fully operational as advertised!" src="http://blog.hoegaerden.be/wp-content/uploads/image447.png" width="700" height="200" /></p>
<p><strong>Conclusion:</strong> it’s not a good idea to leave the Maximum setting in the Horizontal Axis Properties set to “Auto”.</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&#39;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>
<p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.hoegaerden.be%2F2010%2F05%2F27%2Fimplementing-data-bars-in-a-grouped-table%2F&amp;title=Implementing%20Data%20Bars%20In%20A%20Grouped%20Table" id="wpa2a_20"><img src="http://blog.hoegaerden.be/wp-content/plugins/add-to-any/share_save_171_16.png" width="171" height="16" alt="Share"/></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>10</slash:comments>
		</item>
	</channel>
</rss>

