<?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>Data Inspirations &#187; MDX</title>
	<atom:link href="http://blog.datainspirations.com/tag/mdx/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.datainspirations.com</link>
	<description>Inspiring Intelligence from Information</description>
	<lastBuildDate>Thu, 02 Feb 2012 01:12:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>SQLU MDX Week: A Gentle Introduction to Sets</title>
		<link>http://blog.datainspirations.com/2011/12/16/sqlu-mdx-week-an-introduction-to-sets/</link>
		<comments>http://blog.datainspirations.com/2011/12/16/sqlu-mdx-week-an-introduction-to-sets/#comments</comments>
		<pubDate>Fri, 16 Dec 2011 12:51:15 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[SQL University]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/?p=611</guid>
		<description><![CDATA[Welcome to my third post in a series of topics on MDX for SQL University. If you&#8217;re just now joining me, you should check out the first post, Location, Location, Location, and my previous post, Writing Simple Queries, to get oriented. I&#8217;m going to continue building on the concepts introduced in the earlier posts by showing [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sqlchicken.com/sql-university" target="_blank"><img class="size-full wp-image-428 alignleft" title="SQL University" src="http://blog.datainspirations.com/wp-content/uploads/2011/05/SQL_University.png" alt="" width="175" height="200" /></a><br />
Welcome to my third post in a series of topics on MDX for <a href="http://sqlchicken.com/sql-university/" target="_blank">SQL University</a>. If you&#8217;re just now joining me, you should check out the first post, <a title="SQLU MDX Week: Location, Location, Location" href="http://blog.datainspirations.com/2011/12/13/sqlu-mdx-week-location-location-location/" target="_blank">Location, Location, Location</a>, and my previous post, <a title="SQLU MDX Week: Writing Simple Queries" href="http://blog.datainspirations.com/2011/12/14/sqlu-mdx-week-writing-simple-queries/" target="_blank">Writing Simple Queries</a>, to get oriented. I&#8217;m going to continue building on the concepts introduced in the earlier posts by showing you how to use functions to create a set to use on an axis.</p>
<p>Many times you&#8217;re interested in seeing values for all of the members of a particular attribute hierarchy. For example, in this query, we can see sales for all categories and for all years, including a grand total for categories and years and also years that have no sales.</p>
<pre>SELECT
[Date].[Calendar Year].Members
 ON COLUMNS,
[Product].[Category].Members ON ROWS
FROM [Adventure Works]
WHERE [Measures].[Sales Amount]</pre>
<p style="text-align: center;"><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-05.gif"><img class="aligncenter size-full wp-image-613" title="mdx-05" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-05.gif" alt="" width="529" height="112" /></a></p>
<p>When you use the Members function with a dimension and hierarchy, you get everything listed in the Members folder:</p>
<p style="text-align: center;"><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/members.gif"><img class="aligncenter size-full wp-image-614" title="members" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/members.gif" alt="" width="204" height="193" /></a></p>
<p>What if you don&#8217;t want the All Periods member to show up? Well, you could create a set like this {[Date].[Calendar].[CY 2005], [Date].[Calendar.[CY 2006], &#8230;} but that would be tedious, and it wouldn&#8217;t automatically include new members that get added to the dimension over time. Instead, you can use the Members function with the dimension, hierarchy, and level reference to skip over the All Periods like this:</p>
<pre>SELECT
[Date].[Calendar Year].[Calendar Year].Members
 ON COLUMNS,
[Product].[Category].Members ON ROWS
FROM [Adventure Works]
WHERE [Measures].[Sales Amount]</pre>
<p style="text-align: center;"><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-06.gif"><img class="aligncenter size-full wp-image-615" title="mdx-06" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-06.gif" alt="" width="450" height="97" /></a></p>
<p>Here we have a case of &#8220;more is less.&#8221; When we use a level reference, such as we do with the expression [Date].[Calendar Year].[Calendar Year].Members, we are providing more specific instructions to the Members function so that we can get less data. Using a level reference works with both attribute hierarchies (the ones with two levels only) and user-defined hierarchies (the ones with multiple levels and a pyramid-shaped icon).</p>
<p style="text-align: center;"><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/level-members.gif"><img class="aligncenter size-full wp-image-616" title="level-members" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/level-members.gif" alt="" width="198" height="230" /></a></p>
<p>One more little change to this query might make it better. If we don&#8217;t want to see CY 2009 and CY 2010 columns when they are empty, we add the NON EMPTY keyword in front of the set definition like this:</p>
<pre>SELECT
NON EMPTY [Date].[Calendar Year].[Calendar Year].Members
 ON COLUMNS,
[Product].[Category].Members ON ROWS
FROM [Adventure Works]
WHERE [Measures].[Sales Amount]</pre>
<p>What if we want to see the category sales broken down not only by year, but also by sales territory? We can combine sets on an axis using the CrossJoin function like this:</p>
<pre>SELECT
NON EMPTY [Date].[Calendar Year].[Calendar Year].Members
 ON COLUMNS,
NON EMPTY
CrossJoin([Product].[Category].Members,
	[Sales Territory].[Sales Territory Group].[Sales Territory Group].Members)
ON ROWS
FROM [Adventure Works]
WHERE [Measures].[Sales Amount]</pre>
<pre><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-07.gif"><img class="aligncenter size-full wp-image-619" title="mdx-07" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-07.gif" alt="" width="423" height="248" /></a></pre>
<p>The CrossJoin function takes only two arguments, but you can use that expression as one argument in a second CrossJoin function to create a grouping of three dimension hierarchies on an axis. There are several ways to get the crossjoin effect which might be easier to read when you start adding more dimension hierarchies to the mix. One is the use of a &#8220;polymorphic operator&#8221; such as an asterisk * like this:</p>
<pre>[Product].[Category].Members *
[Sales Territory].[Sales Territory Group].[Sales Territory Group].Members</pre>
<p>The other is to create a tuple set like this:</p>
<pre>([Product].[Category].Members,
[Sales Territory].[Sales Territory Group].[Sales Territory Group].Members)</pre>
<p>I know I said in a previous post that a tuple is like a coordinate to a cell, and it appears in the above example that I&#8217;m violating that rule by using sets in a tuple. But Analysis Services resolves this expression as a set of tuples by taking every member of the first set (the product category members) to create a tuple with every member of the second set (sales territory group members).  That set gets placed on the rows axis and the set of calendar year members gets placed on the columns axis, and then the tuple coordinates for each intersection of a row and a column produces a new tuple definition that generates a result, such as $709,947.20 for the pseudo-tuple (All Products, Europe, CY 2005).</p>
<p>There are many more functions that we can use to generate sets to control what we see on rows or columns. More than I can cover in this post. (In fact, there are entire books that cover this topic. In a future post, I&#8217;ll provide some recommendations.) For now, I&#8217;ll leave you with one more function to add to your repertoire. This time we want to see only those product categories and sales territory combinations that have sales greater than $1 million in CY 2008, but we want to see their sales for all years. To do this, we use the Filter function. This should satiate your desire to use a WHERE clause in your query, which I told you in my previous post does not work like a filter as it does in a T-SQL query.</p>
<pre>SELECT
NON EMPTY [Date].[Calendar Year].[Calendar Year].Members
 ON COLUMNS,
Filter(
	([Product].[Category].[Category].Members,
		[Sales Territory].[Sales Territory Group].[Sales Territory Group].Members),
	([Measures].[Sales Amount],[Date].[Calendar Year].&amp;[2008])  &gt; 1000000)
ON ROWS
FROM [Adventure Works]
WHERE [Measures].[Sales Amount]</pre>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-08.gif"><img class="aligncenter size-full wp-image-620" title="mdx-08" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-08.gif" alt="" width="520" height="98" /></a></p>
<p>The Filter function takes two arguments. The first is the set that you want to filter. And the second is a Boolean expression that determines which members will be in the set that the Filter function produces. In this case, I used a tuple expression to focus on the 2008 sales.  If I had used only Sales Amount, the filter would have produced a set of category/territory combinations having total sales for all years greater than $1 million.</p>
<p>The key concept to take away from this post is that sets go on rows and columns, and that we can control very precisely which members are in those sets by using functions and tuple sets. A very common function to use is the Members function, and it&#8217;s also common to use NON EMPTY to rid ourselves of rows or columns that contain only null values.</p>
<pre></pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2011/12/16/sqlu-mdx-week-an-introduction-to-sets/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>SQLU MDX Week: Writing Simple Queries</title>
		<link>http://blog.datainspirations.com/2011/12/14/sqlu-mdx-week-writing-simple-queries/</link>
		<comments>http://blog.datainspirations.com/2011/12/14/sqlu-mdx-week-writing-simple-queries/#comments</comments>
		<pubDate>Wed, 14 Dec 2011 16:57:55 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[SQL University]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/?p=601</guid>
		<description><![CDATA[This post is the second in a series of topics on MDX for SQL University. In my first post, Location, Location, Location, I introduced the tuple as a way to retrieve data from a cube with very precise instructions about what you want. In this post, I&#8217;m going to show you how to do that by [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sqlchicken.com/sql-university" target="_blank"><img class="size-full wp-image-428 alignleft" title="SQL University" src="http://blog.datainspirations.com/wp-content/uploads/2011/05/SQL_University.png" alt="" width="175" height="200" /></a><br />
This post is the second in a series of topics on MDX for <a href="http://sqlchicken.com/sql-university/" target="_blank">SQL University</a>. In my first post, <a title="SQLU MDX Week: Location, Location, Location" href="http://blog.datainspirations.com/2011/12/13/sqlu-mdx-week-location-location-location/" target="_blank">Location, Location, Location</a>, I introduced the tuple as a way to retrieve data from a cube with very precise instructions about what you want. In this post, I&#8217;m going to show you how to do that by writing queries. One thing that you will have to promise me as you read this post is to forget what you know about SQL queries (presuming you have some knowledge in that area). It will mess you up. If you start with a clean slate, you will have an easier time of it.</p>
<h3>Preparing the Query Environment</h3>
<p>Before I dive into writing queries, let me explain the setup. I&#8217;m using SQL Server 2008 R2 Analysis Services for these examples. You can work with earlier versions, but in some cases you will encounter date ranges that are four years earlier than the date shown in my examples. For example, instead of using Q3 2007, you would need to use Q3 2004. The measure values will remain the same. Here are links to the samples that you need to have installed:</p>
<ul>
<li style="text-align: left;">If using Microsoft SQL Server 2005, install the sample databases (AdventureWorks, AdventureWorksDW)</li>
<li style="text-align: left;">If using a later version, download the sample databases from <a href="http://msftdbprodsamples.codeplex.com/">http://msftdbprodsamples.codeplex.com/</a>, install the databases, and then follow the instructions at <a href="http://msftdbprodsamples.codeplex.com/wikipage?title=Installing%20Analysis%20Services%20Database">http://msftdbprodsamples.codeplex.com/wikipage?title=Installing%20Analysis%20Services%20Database</a> to install and deploy the Analysis Services database.</li>
</ul>
<h3>Requesting a Tuple from a Cube</h3>
<p>Okay, let&#8217;s start simple. Very, very simple. Go to SQL Server Management Studio, connect to Analysis Services, and click the MDX button on the query toolbar. An MDX query editor window will open. In the Available Databases drop-down list, select the Adventure Works database for your version of SSAS.</p>
<p>To retrieve a tuple from the cube named Adventure Works, you write a query like this:</p>
<pre>SELECT FROM [Adventure Works] 
WHERE
([Product].[Product].&amp;[359],[Date].[Date].[January 1, 2008],[Measures].[Sales Amount])</pre>
<p><span class="Apple-style-span" >Notice the way that I refer to dimension members here. I&#8217;m no longer writing a pseudo-tuple as I did in my previous post, but am now using member unique names which tells Analysis Services the dimension and  hierarchy to which the member belongs. If you leave out the dimension and hierarchy, you will still get an answer, but no guarantee that you have the right answer if it&#8217;s possible that another dimension and hierarchy contain a member of the same name. For example, what if I have a West region and a sales person with the last name of West? Analysis Services will use one or the other to construct the tuple. The only way I can control which one is to use the dimension and hierarchy name. In fact, I switched from using Mountain-200 Black, 38 to [Product].[Product].&amp;[359] because there are two products with the name Mountain-200 Black, 38 (due to Slowly Changing Dimensions) and I want the one that actually has sales for January 1, 2008. I can refer to members not only by name, but by the value in the key column &#8211; which in this case is the surrogate key for the dimension. I use an ampersand before the key value wrapped in brackets to specify that it&#8217;s a key column in the tuple rather than a member name .</span></p>
<p>Now let&#8217;s see the results of the query. Press F5 or the Execute button in the toolbar to see a single value appear in the Results pane.</p>
<p><strong><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-01.gif"><img class="aligncenter size-full wp-image-603" title="mdx-01" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-01.gif" alt="" width="154" height="52" /></a><br />
</strong></p>
<p>The WHERE clause in your query contains the tuple that you want to retrieve. It does NOT behave like a WHERE clause in a SQL query, which is why I asked you nicely to forget about that other language &#8211; at least for the duration of this post. The problem with requesting a tuple this way is that the result does not include any metadata that tells me what I&#8217;m looking at. So I can enhance this query by showing one of the members of the tuple as a column label and one of the other members of the tuple as a row label, like this:</p>
<pre>SELECT 
[Date].[Date].[January 1, 2008] ON COLUMNS,
[Product].[Product].&amp;[359] ON ROWS
FROM [Adventure Works] 
WHERE [Measures].[Sales Amount]</pre>
<p>Press F5 to see that the result of the query is the same, but now we have some more context for the value that displays.</p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-02.gif"><img class="aligncenter size-full wp-image-604" title="mdx-02" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-02.gif" alt="" width="232" height="68" /></a></p>
<p>The way that I like to think about the query results for this example is that it works in three phases. First, Analysis Services retrieves my request for the member on columns. Second, it retrieves my request for the member on rows. Those two steps occur completely independently of one another. Third, Analysis Services looks at the intersections produced by placing member on columns and rows and adds in the WHERE clause to produce a tuple. That&#8217;s why we get the same value in the result. It doesn&#8217;t matter which member you put on columns and which member you put on rows and which you leave in the WHERE clause. Collectively, they produce a tuple.</p>
<p>You don&#8217;t have to use a WHERE clause in the query. Instead, you could put everything onto an axis &#8211; either rows or columns. Essentially, you&#8217;re moving the tuple fragments out of the WHERE clause onto an axis. The tuple produced by the query parser is the same, but we get more metadata in the results to see the context of the query. For example, try this:</p>
<pre>SELECT 
([Date].[Date].[January 1, 2008], [Measures].[Sales Amount]) ON COLUMNS,
[Product].[Product].&amp;[359] ON ROWS
FROM [Adventure Works]</pre>
<p>Here you see the results of the new query.</p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-03.gif"><img class="aligncenter size-full wp-image-605" title="mdx-03" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-03.gif" alt="" width="229" height="87" /></a></p>
<p>You can put any member of the tuple on either rows or columns. You can even write the query to show rows first and columns second like this:</p>
<pre>SELECT 
[Product].[Product].&amp;[359] ON COLUMNS,
([Date].[Date].[January 1, 2008], [Measures].[Sales Amount]) on ROWS
FROM [Adventure Works]</pre>
<p>But the result of your query stays the same. You can have a query that only has a tuple fragment on columns like this:</p>
<pre>SELECT 
([Date].[Date].[January 1, 2008], [Measures].[Sales Amount]) ON COLUMNS
FROM [Adventure Works]</pre>
<p>But you cannot have a query that has a tuple fragment on rows like this:</p>
<pre>SELECT 
([Date].[Date].[January 1, 2008], [Measures].[Sales Amount]) ON ROWS
FROM [Adventure Works]</pre>
<p>If I don&#8217;t ask for something in a tuple explicitly by putting it on columns, on rows, or in the WHERE clause, Analysis Services plugs in the All member for the dimension and hierarchy that I didn&#8217;t include. Usually. There is an exception but we&#8217;ll save that explanation for another post. This behavior is especially helpful when you have lots of dimensions and hierarchies. Otherwise, you&#8217;d have a tuple that is  ginormous (your new technical term for the day).</p>
<h3>Using Sets in a Query</h3>
<p>Asking for data one tuple at a time is rather tedious. Fortunately, we can take our knowledge about query construction to the next level. Technically speaking, when we put a member on columns or rows, we were asking for a set. A set of one. When we put the tuple fragment on columns or rows, we were creating a tuple set. Another option is to explicitly create a set like this:</p>
<pre>SELECT
{[Date].[Date].[January 1, 2008], [Date].[Date].[February 1, 2008]} ON COLUMNS,
[Product].[Product].&amp;[359] ON ROWS
FROM [Adventure Works]
WHERE [Measures].[Sales Amount]</pre>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-04.gif"><img class="aligncenter size-full wp-image-607" title="mdx-04" src="http://blog.datainspirations.com/wp-content/uploads/2011/12/mdx-04.gif" alt="" width="305" height="43" /></a></p>
<p>Whereas we use parentheses to denote a tuple, we use braces to denote a set. The order in which we define the member of the set determines the order in which the members display in the results. Try changing the sequence of members in the set to see the results.</p>
<p>MDX provides us with lots of functions to produce sets or to produce members that we use in sets so that we don&#8217;t have to list out members explicitly in a query. In my next post, we&#8217;ll explore some some of these functions.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2011/12/14/sqlu-mdx-week-writing-simple-queries/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Book Review: MDX with Microsoft SQL Server 2008 R2 Analysis Services Cookbook</title>
		<link>http://blog.datainspirations.com/2011/10/21/book-review-mdx-with-microsoft-sql-server-2008-r2-analysis-services-cookbook/</link>
		<comments>http://blog.datainspirations.com/2011/10/21/book-review-mdx-with-microsoft-sql-server-2008-r2-analysis-services-cookbook/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 19:39:49 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Book Review]]></category>
		<category><![CDATA[MDX]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/2011/10/21/book-review-mdx-with-microsoft-sql-server-2008-r2-analysis-services-cookbook/</guid>
		<description><![CDATA[As I mentioned in an earlier post, I first met Tomislav Piasevoli’s (blog&#124;twitter) in 2008 at the PASS Summit in Seattle, and saw him again most recently again in Seattle at PASS Summit 2011. There I had the pleasure of telling him personally how much I liked his book. There are not many MDX books [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.packtpub.com/mdx-with-microsoft-sql-server-2008-r2-analysis-services/book"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; float: left; padding-top: 0px; border: 0px;" title="1308EN_MDX with Microsoft SQL Server Analysis Services 2008 R2 Cookbook" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/Book-Review-MDX-with-Microsoft-SQL-Serve_857B/1308EN_MDX-with-Microsoft-SQL-Server-Analysis-Services-2008-R2-Cookbook_thumb.png" border="0" alt="1308EN_MDX with Microsoft SQL Server Analysis Services 2008 R2 Cookbook" width="125" height="152" align="left" /></a></p>
<p>As I mentioned in <a href="http://blog.datainspirations.com/2011/09/09/back-to-the-future-with-mdx-and-pass/" target="_blank">an earlier post</a>, I first met Tomislav Piasevoli’s (<a href="http://tomislav.piasevoli.com/" target="_blank">blog</a>|<a href="http://twitter.com/tpiasevoli" target="_blank">twitter</a>) in 2008 at the PASS Summit in Seattle, and saw him again most recently again in Seattle at <a href="http://www.sqlpass.org/summit/2011/" target="_blank">PASS Summit 2011</a>. There I had the pleasure of telling him personally how much I liked his book. There are not many MDX books available, so when a new one arrives on the market, I definitely want to take a look. Now I have taught MDX classes for many years, and I think perhaps my first class was in 2002. However, it’s been so long now, I don’t recall exactly when that first class was. What I do know is that my understanding of MDX and my fluency with the language has grown by leaps and bounds since then through experience with all kinds of bleeding edge MDX, and I have tried to communicate some of my insights developed along the way to students in my classroom. MDX concepts can stretch your thinking (to put it mildly), and more so if you have to unlearn SQL concepts as well, which is true of the majority of my students. As a native English speaker, I can find it challenging at times to explain certain aspects of MDX. For all these reasons, I can fully appreciate Tomislav’s efforts to create this book and commend him for his excellent examples and explanations using a language that is not his mother tongue.</p>
<p>Tomislav’s book is definitely not for beginners. There is an underlying assumption that you already have some familiarity with the basics of MDX. The purpose of this book is to provide you with the tools necessary to continue building your skills. The chapters group together a series of related concepts, called recipes. You don’t need to read the book sequentially from cover to cover. Instead, you search for the desired outcome, such as handling division by zero errors (described in Chapter 1) or calculating row numbers (found in Chapter 7). Ideally, you don’t just read the recipe, but actually try out the steps yourself. I did some of my reading of this book when I was away from my laptop, and frequently found that I wanted to try out something that Tomislav mentioned. Even long-time MDX developers like myself can find interesting tidbits of information to round out their repertoire!</p>
<p>Each concept within a chapter is presented in a similar manner, beginning with “Getting ready” which are the steps you need to perform to set up your query. For example, you might need to work in Management Studio and set up a query as a starting point or open the Script View for a cube in Business Intelligence Development Studio. Then the next section is “How to do it…” which provides step-by-step instructions for working with a query or MDX script to accomplish the intended outcome. Then Tomislav continues with the “How it works…” section which provides background information on the key concepts for the current recipe. This section is the real meat of the book, but is nicely separated from the implementation steps if you want to jump straight to the technical details. Depending on the recipe, Tomislav also includes additional sections, such as “There’s more…” to provide alternative solutions or to point you to helpful links on the Internet such as whitepapers and blog articles providing more insight, and “See also…” to cross-reference you to another recipe in the book that covers a closely related concept.  Where applicable, he also includes information about how the techniques in the recipe behave differently in earlier versions of Analysis Services.</p>
<h5>Chapter 1: Elementary MDX Techniques</h5>
<p>Don’t let the word Elementary fool you into thinking you can learn entry-level MDX from this chapter. As I mentioned earlier, this book is not for beginners. There are good techniques here and a few basics, such as a great explanation of the FORMAT_STRING property and troubleshooting its use. However, I would consider the majority of these techniques to be elementary only as compared to the other techniques found later in the book. For example, the WHERE clause is one of those things that I see people really get into a tangle over (because they can’t forget their T-SQL), and Tomislav demonstrates using it to implement a logical OR on members from different hierarchies and a logical AND for members from the same hierarchy. One of my favorite sections in this chapter is the coverage of alternatives for the FILTER() function, which can cause performance problems. Use this chapter to get grounded with some foundational concepts, then strap on your seatbelt before diving into the rest of the book!</p>
<h5>Chapter 2: Working with Time</h5>
<p>Time is something that every cube has. Or at least every cube that I’ve ever met. I can’t imagine a cube without one (even if it’s called Date) because often business analysis is comparing one period to another or monitoring trends over time. Tomislav starts with the basics of the YTD() function but delves into variations on the theme and points out pitfalls to avoid. He moves on to parallel periods, moving averages, and finding last dates with data, among other time-related topics. A useful recipe in this chapter is the use of string functions to calculate a date, as I see this requirement a lot when working with Reporting Services reports that use Analysis Services as a source. A good case for working with a single-member named set rather than a calculated member is also made in this chapter.</p>
<h5>Chapter 3: Concise Reporting</h5>
<p>A report in this chapter means a pivot table used in some front-end tool for Analysis Services, and not Reporting Services exclusively. The goal of this chapter is to reduce the size of the pivot table, and thereby improve performance. I would characterize this chapter as one that helps you find the best or the worst members in a group, whether in a hierarchy, among siblings, or among descendants. Tomislav starts off the chapter with a recipe to get the top N members. In this recipe, Tomislav includes a great explanation of what can go wrong when you use the TopCount() function. Well, it’s not a matter of it behaving incorrectly because it’s doing what you ask. The problem is that many people misunderstand how the TopCount() function behaves under certain conditions and Tomislav delves deeply into the behavior here. He then builds on these ideas throughout the chapter and introduces alternatives for finding and displaying the best and the worst.</p>
<h5>Chapter 4: Navigation</h5>
<p>Hierarchies in a dimension are extremely useful for a number of reasons, one of which is navigation. The chapter begins with some simple queries that use Boolean logic to test the context of a current member on the row axis, and then expands to use scoping in the MDX script or use a query (using CELL CALCULATION) to determine if members are in the same branch of a hierarchy. Are you confused about when to use the Exists() function and the EXISTING keyword? Tomislav covers them both in this chapter in a variety of contexts. Also, having advocated on behalf of a named set in a previous chapter, Tomislav explores the pros and cons of named sets more fully in this chapter.</p>
<h5>Chapter 5: Business Analytics</h5>
<p>This chapter covers several techniques that are encountered less frequently (depending on who you ask, I suppose) than those covered up to this point in the book. For example, the chapter begins with linear regression which I’ve never had to use in 10 years of writing MDX. But I said the same about the Correlation() function once upon a time and I now use it frequently in a current project, so my feeling is that you never know when you’ll need to use a seemingly obscure function. Because these analytical functions are used less commonly, the amount of information available through Books Online or elsewhere on the Internet is pretty slim. Therefore, having this chapter’s working examples at your fingertips is invaluable. Also covered in this chapter is adjusting forecasts based on periodic cycles, alternative approaches to expense allocations, finding slow-moving inventory items, categorizing customers, and ABC analysis (which is an application of Pareto analysis).</p>
<h5>Chapter 6: When MDX is Not Enough</h5>
<p>In this chapter, Tomislav makes the case that when an MDX approach gets overly complicated, it’s time to look at making changes to the dimension or cube design. For example, he says, “Every time you catch yourself using functions like Except(), Filter(), or similar() too often in your calculations, you should step back and consider whether that’s a repeating behavior and whether it would pay off to have an attribute to separate the data you’ve been separating using MDX calculations.” He also explains how and why to create a placeholder measure in the cube to use with assignments in the MDX script. Utility dimensions for unit conversion or for time-based calculations are also covered in this chapter.</p>
<h5>Chapter 7: Context-aware Calculations</h5>
<p>Understanding context is an important aspect of MDX development. As Tomislav explains in the introduction to this chapter, context can be unpredictable based on what a user might select to place on rows and columns, or it can be partially known when you expect a particular measure or hierarchy to be used, or it can be completely known. The trick is to produce a calculation that behaves correctly regardless of context, which can be made trickier based on a combination of factors that Tomislav describes. The recipes in this chapter help you explore context from a number of, um, contexts, starting with how to know how many columns and rows will be in a query’s result set, how to determine which axis contains measures, how to determine what has been placed on an axis, among other useful techniques.</p>
<h5>Chapter 8: Advanced MDX Topics</h5>
<p>Now frankly I considered several of the recipes up to this point to be advanced, so I had to chuckle at the title of this chapter. Let’s just say these recipes are more complex! In this chapter, you’ll find techniques for working with parent-child hierarchies and displaying random values for sampling purposes. Hopefully, you’re avoiding the use of parent-child hierarchies and random sampling is not a common request in reports, so this section of the chapter is interesting primarily from an academic viewpoint. But then we move to complex sorts – a very useful subject indeed. Tomislav provides several examples and highlights potential problem areas. Also in this chapter is a recipe for recursively calculating cumulative values.</p>
<h5>Chapter 9: On the Edge</h5>
<p>Tomislav uses this chapter to collect topics that don’t neatly fit into the earlier chapters. Here he covers Analysis Services stored procedures (which are nothing like T-SQL stored procedures, by the way), as well as using the OPENQUERY() and OPENROWSET() functions for calling MDX from a T-SQL statement. He also introduces Dynamic Management Views (DMVs) for documenting and monitoring cubes, and shows how to use SQL Server Profiler to capture MDX queries. Last, he shows how to use the DRILLTHROUGH command.</p>
<p>If you’re an MDX developer, whether brand new or experienced, you will find lots of good information in this book and practical examples of how and why to implement specific techniques. I definitely recommend that you add it to your library, in whatever format you prefer. It’s available in <a href="http://www.packtpub.com/mdx-with-microsoft-sql-server-2008-r2-analysis-services/book" target="_blank">paperback, PDF, ePub and Mobi from the publisher</a> and in <a href="http://www.amazon.com/Microsoft-Analysis-Services-Cookbook-ebook/dp/B005HIK89S/ref=sr_1_2?ie=UTF8&amp;qid=1319215803&amp;sr=8-2" target="_blank">Kindle format from Amazon</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2011/10/21/book-review-mdx-with-microsoft-sql-server-2008-r2-analysis-services-cookbook/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Back to the Future with MDX and PASS</title>
		<link>http://blog.datainspirations.com/2011/09/09/back-to-the-future-with-mdx-and-pass/</link>
		<comments>http://blog.datainspirations.com/2011/09/09/back-to-the-future-with-mdx-and-pass/#comments</comments>
		<pubDate>Fri, 09 Sep 2011 19:35:44 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[PASS]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/2011/09/09/back-to-the-future-with-mdx-and-pass/</guid>
		<description><![CDATA[An interesting confluence of events this week takes me both back to the past as I ponder the future! What gives? Well, the recent release of Tomislav Piasevoli’s (blog&#124;twitter) new book, MDX with Microsoft SQL Server 2008 R2 Analysis Services Cookbook, reminded me of my first meeting with him at a PASS Summit event a [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.packtpub.com/mdx-with-microsoft-sql-server-2008-r2-analysis-services/book?utm_source=blog.datainspirations.com&amp;utm_medium=bookrev&amp;utm_content=blog&amp;utm_campaign=mdb_009319"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; float: left; padding-top: 0px; border-width: 0px;" title="1308EN_MDX with Microsoft SQL Server Analysis Services 2008 R2 Cookbook" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/Back-to-the-Future-with-MDX-and-PASS_A4CA/1308EN_MDX-with-Microsoft-SQL-Server-Analysis-Services-2008-R2-Cookbook.png" border="0" alt="1308EN_MDX with Microsoft SQL Server Analysis Services 2008 R2 Cookbook" width="136" height="165" align="left" /></a>An interesting confluence of events this week takes me both back to the past as I ponder the future! What gives? Well, the recent release of Tomislav Piasevoli’s (<a href="http://tomislav.piasevoli.com/" target="_blank">blog</a>|<a href="http://twitter.com/tpiasevoli" target="_blank">twitter</a>) new book, <em><a href="http://www.packtpub.com/mdx-with-microsoft-sql-server-2008-r2-analysis-services/book?utm_source=blog.datainspirations.com&amp;utm_medium=bookrev&amp;utm_content=blog&amp;utm_campaign=mdb_009319" target="_blank">MDX with Microsoft SQL Server 2008 R2 Analysis Services Cookbook,</a></em> reminded me of my first meeting with him at a PASS Summit event a few years ago. Alas, I don’t remember which event because – I confess – I’m getting old and my brain just doesn’t store details like that anymore. Not when it’s full of more important tidbits more necessary to my daily work! If I had to guess, I think it was the first event that Erika attended with me, which means it would have been in 2008 but it could have been 2009, and definitely not 2010. How’s that for narrowing it down? [Edit: Tomislav reminded me that we actually met at the 2008 PASS Summit but we talked about the Axis function at the 2009 PASS Summit Birds of a Feather.]</p>
<p>Regardless of which year it was, Tomislav was seated at table during a Birds of a Feather lunch talking to several people about MDX, and he made a comment about the Axis function which I thought was very interesting. To be honest, I don’t remember what he said specifically, but it intrigued me enough to jot it down to pursue at a later time. It turned out not to be helpful for whatever MDX problem I was faced with at the time, but I kept the note to myself in my smartphone, which transferred over to the next two smartphones I’ve owned since then. My experience with MDX is that there are a handful of MDX functions that we who are inclined to write MDX use quite often. For an interesting, but entirely unscientific, analysis of function popularity, see this 2005 post from Mosha Pasumansky, “<a href="http://sqlblog.com/blogs/mosha/archive/2005/01/31/what-are-the-popular-mdx-functions.aspx">What are the popular MDX functions?</a>” Although the post is a bit dated, I think it’s still valid. When I look at the top list of functions, I do indeed use many of those functions frequently (although NonEmptyCrossJoin is deprecated and I now use the NonEmpty function instead).</p>
<p>This year, I finally found a situation where I found the <a href="http://msdn.microsoft.com/en-us/library/ms145531.aspx">Axis</a> function to be useful. Basically, this function gives us a way to “see” what’s currently on rows or columns. The situation facing me was  to come up with a way to create a calculation based on values found in two columns in a pivot table. More specifically, each column could be a different time period. So the calculation might be comparing Q1 and Q2 of a particular year, or it might be Q1 of one year and Q2 of another year. But we would not know in advance which two time periods would be involved. I built a calculation to count how many date members were on the columns axis and return a null if there were more than two, otherwise to do the math. I’ll provide the details for this in a separate post, but there are other scenarios in which this function is useful as Tomislav explains in this SQLBits session (recording freely accessible, slides and samples downloadable): <a href="http://sqlbits.com/Sessions/Event4/Universal_calculated_measures_in_MDX_queries">Universal calculated measures in MDX queries</a>.</p>
<p>That encounter with Tomislav is just one example of many that highlights the value of attending the <a href="http://www.sqlpass.org/summit/2011/">PASS Summit</a>. It’s not just what you learn by attending the sessions, but also what you learn in casual conversations with experts. Opportunities abound for these conversations, whether at a <a href="http://www.sqlpass.org/summit/2011/Connect/SpecialEvents.aspx#BOF_Lunch">Birds of a Feather</a> table or in the hallway or at one of the <a href="http://www.sqlpass.org/summit/2011/Connect/AfterHours.aspx">many evening events</a>. (Hint: Asking questions during <a href="http://www.sqlkaraoke.com/">SQLKaraoke</a> is probably not a good time.) People who are at PASS – both speakers and non-speakers alike – are there because they’re passionate about what they do. If you plan to go and it’s your first time, the best advice I can give is Don’t Be Shy! Talk to someone, anyone, everyone! You won’t regret it.</p>
<p>It’s only a few more short weeks until Erika and I head out to this year’s summit. I’ve got to finalize my demos for my preconference workshop on <a href="http://www.sqlpass.org/summit/2011/Speakers/CallForSpeakers/SessionDetail.aspx?sid=1491">MDX, DAX, and DMX</a> and for my half-day session with Denny Cherry, <a href="http://www.sqlpass.org/summit/2011/Speakers/CallForSpeakers/SessionDetail.aspx?sid=1134">So How Does the BI Workload Impact the Database Engine?.</a> I think all I need to do is show up for my panel session, <a href="http://www.sqlpass.org/summit/2011/Speakers/CallForSpeakers/SessionDetail.aspx?sid=1509">Are You a Linchpin?</a></p>
<p>Meanwhile, I’m going to be reading Tomislav’s new book to see what other gems he has to share, and I’ll post a review when I finish the book. Stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2011/09/09/back-to-the-future-with-mdx-and-pass/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>SQLU MDX Week: Location, Location, Location</title>
		<link>http://blog.datainspirations.com/2011/05/11/sqlu-ssas-week-why-do-i-need-a-cube-how-do-i-get-started/</link>
		<comments>http://blog.datainspirations.com/2011/05/11/sqlu-ssas-week-why-do-i-need-a-cube-how-do-i-get-started/#comments</comments>
		<pubDate>Wed, 11 May 2011 11:15:00 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[SQL University]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/?p=427</guid>
		<description><![CDATA[Once again, I am serving as the professor at SQL University during MDX week. MDX stands for MultiDimension eXpression language and we use it to add business logic to cubes in the form of calculations, named sets, and KPIs as well as to configure security and to write reports. I can’t teach you everything you [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://sqlchicken.com/sql-university" target="_blank"><img class="size-full wp-image-428 alignleft" title="SQL University" alt="" src="http://blog.datainspirations.com/wp-content/uploads/2011/05/SQL_University.png" width="175" height="200" /></a>Once again, I am serving as the professor at <a href="http://sqlchicken.com/sql-university/" target="_blank">SQL University</a> during MDX week. MDX stands for MultiDimension eXpression language and we use it to add business logic to cubes in the form of calculations, named sets, and KPIs as well as to configure security and to write reports. I can’t teach you everything you need to know about MDX in just a few blog posts this week, but I can help you get into the right frame of mind to learn MDX, to get some insight into how the language works, and where to learn more to further your studies. </p>
<p>Before you undertake MDX, you should know something about Analysis Services and cubes. Earlier this year, I presented a series of posts as part of SQL&#160; University to introduce you to this topic:</p>
<ul>
<li><a href="http://blog.datainspirations.com/2011/05/11/sqlu-ssas-week-why-do-i-need-a-cube-how-do-i-get-started/" target="_blank">Why Do I Need a Cube and How Do I Get Started?</a></li>
<li><a href="http://blog.datainspirations.com/2011/05/11/sqlu-ssas-week-dimension-design-101-2/" target="_blank">Dimension Design 101</a></li>
<li><a href="http://blog.datainspirations.com/2011/05/12/sqlu-ssas-week-cube-construction-101/" target="_blank">Cube Construction 101</a></li>
<li><a href="http://blog.datainspirations.com/2011/05/15/sqlu-ssas-week-cube-enhancements-101/" target="_blank">Cube Enhancements 101</a></li>
<li><a href="http://blog.datainspirations.com/2011/05/17/sqlu-ssas-week-cube-deployment-101/" target="_blank">Cube Deployment 101</a></li>
</ul>
<p>Before we dive into using MDX later this week, let’s start with perhaps the most fundamental concept that you need to understand – location, location, location.</p>
<h3><strong>Build On What You Know</strong></h3>
<p>You’ve probably used an Excel spreadsheet at some point and are familiar with using cell references to create formulas. For example, in the spreadsheet below, if I want to perform a calculation that includes the sales for the product “Mountain-200 Black, 38” on 1/1/2008, I would use the formula =B2. The letter B stands for the column reference and the number 2 stands for the row reference. It’s a two-dimensional cell reference. </p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/excel-01.png"><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="excel-01" border="0" alt="excel-01" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/excel-01_thumb.png" width="603" height="148" /></a></p>
<p>“OK,” you’re thinking. “I got that. Rudimentary Excel. What does that have to do with MDX?” Bear with me a little bit longer and I’ll connect the dots for you. </p>
<p>Now consider that I have two sheets in a workbook with a similar layout. One sheet for 2008 sales and one sheet for 2007 sales. I want to calculate total sales for the same product in January. In this case, I can use the formula =’Sales 2008’!B2 + ‘Sales 2007’!B2. I’ve added a third dimension, the sheet name, to the cell references to tell Excel where to find the data for the calculation.</p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/excel-02.png"><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="excel-02" border="0" alt="excel-02" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/excel-02_thumb.png" width="757" height="303" /></a></p>
<p>Let’s continue expanding on this concept:</p>
<ul>
<li>For four dimensions, let’s assume that I have a separate workbook for different stores and I want to combine the sales for all stores for the same product and same month across the two years. My formula would now look like this – ‘[Store A.xlsx]Sales 2008’!B2 + ‘[Store B.xlsx]Sales 2008’!B2 + ‘[Store A.xlsx]Sales 2007’!B2 + ‘[Store B.xlsx]Sales 2007’!B2.</li>
<li>For five dimensions, I might use different folders on the same drive to store workbooks by promotion. So now each workbook reference would look something like this: ‘[C:\Top Customer Promotion\Store A.xlsx]Sales 2008’!B2.</li>
<li>Moving on to six dimensions, I can reference workbooks on different drives.</li>
<li>For seven dimensions, I can reference workbooks on different servers.</li>
</ul>
<p>Now I’m going to get a bit silly, but just use your imagination with me for a moment because I can’t really do this. It’s just expanding the concept of location. Here goes… I can reference workbooks on different servers on different floors (eight dimensions), in different buildings (nine dimensions), on different streets (ten dimensions), in different cities (eleven dimensions), in different states (twelve dimensions), in different countries (thirteen dimensions), on different planets (fourteen dimensions) in different universes (fifteen dimensions)! </p>
<p>Okay, I’ve probably gone a bit too far with this example, and technically speaking, I wouldn’t make each of these aspects of a location into a separate dimension from an Analysis Services point of view. But I want you to get the idea that I can use location references in my Excel formulas to be very precise about which data to include in the formula. Excel understands relative references and absolute references. If you don’t tell it otherwise, it’s going to assume that you want a relative reference. That is, use the current cell, column, sheet,&#160; or whatever that happens to be “current” for the cell in which you are typing the formula unless you give it explicit instructions to use a different cell, columns, sheet, or whatever.</p>
<h3>And Now for the Tuple</h3>
<p>Now let’s bring this back to MDX. A key concept in MDX is the tuple. I say tuh-ple because I learned it that way and I’m too old to change. (Think quintuple, sextuple, octuple – et cetera. The letter u is short the way that I learned.) Some people say too-ple, and that’s okay too. The beauty of reading a blog post is that you can read it with whichever pronunciation you prefer and my pronunciation won’t get in your way!</p>
<p>Let’s move our sales data from Excel into an Analysis Services cube. I’ve simplified the product name because the tire size in there seems to distract people. So “Mountain-200 Black, 38” becomes “Mountain-200 Black.” </p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/tuple-01.png"><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="tuple-01" border="0" alt="tuple-01" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/tuple-01_thumb.png" width="434" height="284" /></a></p>
<p>To get data from a cube, I need to ask for that data in the form of a tuple. A tuple consists of one member from every dimension. So in my two dimensional representation of cube data above, the tuple to get sales for the Mountain-200 Black product in January would be (Mountain-200 Black, 1/1/2008). </p>
<p>Actually, that’s what I call a pseudo-tuple because it’s not exactly the way we would write it in MDX, but I don’t want you to get distracted by the details. For now, let’s focus on the concepts of a tuple.</p>
<p>Tuples are like coordinates that you learned in geometry. If you have a graph with two dimensions, x and y, you represent a point by using the coordinate (x,y). In geometry, order matters – the x must come before the y. But with tuples, order does NOT matter. We can write your example above as either (Mountain-200 Black, 1/1/2008) or (1/1/2008, Mountain-200 Black) and get the same answer: $66,095.71.</p>
<p>Now in our cube, most dimensions have an All level. And that counts as a cell, too. So we can create a tuple (All Products, All Dates) to get the grand total sales: $4,831,250.71.</p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/tuple-02.png"><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="tuple-02" border="0" alt="tuple-02" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/tuple-02_thumb.png" width="447" height="285" /></a></p>
<p>If we have two kinds of measures in our sales, Sales Amount and Order Quantity, then that adds a third dimension to our cube. So our tuple changes accordingly to include the new dimension: (Mountain-200 Black, 1/1/2008, Sales Amount).</p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/tuple-03.png"><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="tuple-03" border="0" alt="tuple-03" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/SQLU-SSAS-Week-Why-Do-I-Need-a-Cube--How_87D9/tuple-03_thumb.png" width="541" height="300" /></a></p>
<p>In summary, a tuple is just a location in a cube. We use it to tell Analysis Services where to find the data that we want. Using MDX functions, we can describe sets of tuples that we want to access “as is” or use in formulas. In my next post, I’ll explain how to write simple MDX queries using this concept of tuples.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2011/05/11/sqlu-ssas-week-why-do-i-need-a-cube-how-do-i-get-started/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Creating a Linked Server for Analysis Services</title>
		<link>http://blog.datainspirations.com/2010/11/30/creating-a-linked-server-for-analysis-services/</link>
		<comments>http://blog.datainspirations.com/2010/11/30/creating-a-linked-server-for-analysis-services/#comments</comments>
		<pubDate>Tue, 30 Nov 2010 23:20:12 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[PASS]]></category>
		<category><![CDATA[SSAS]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/?p=297</guid>
		<description><![CDATA[I think I’ve finally recovered (in more ways than one!) from PASS Summit 2010 in Seattle a mere few weeks ago. I seem to be eternally plagued with computer problems at every conference I attend, but always in different ways. Accordingly, I have devised different strategies for anticipating and coping with problems. I foiled this [...]]]></description>
			<content:encoded><![CDATA[<p>I think I’ve finally recovered (in more ways than one!) from <a href="http://www.sqlpass.org/summit/na2010/" target="_blank">PASS Summit 2010</a> in Seattle a mere few weeks ago. I seem to be eternally plagued with computer problems at every conference I attend, but always in different ways. Accordingly, I have devised different strategies for anticipating and coping with problems. I foiled this last disaster by having my slides and demos duplicated on Erika’s laptop which I had to call into action literally seconds before the session began due to a hard drive failure, but missed one little detail which was actually a last minute bonus addition to my session on <a href="http://msdn.microsoft.com/en-us/library/ms175340(SQL.90).aspx" target="_blank">Analysis Services Stored Procedures</a> (ASSP). So it wasn’t the end of the world, but it was a forehead slapping moment!</p>
<p>As part of that session, I told a story of how I came to appreciate the use of ASSP for a client project in which I had to dynamically construct MDX queries on the fly using T-SQL stored procedures and pass the resulting query into an <a href="http://msdn.microsoft.com/en-us/library/ms188427.aspx" target="_blank">OPENQUERY</a> function. The problem that I had in that situation was the limitation imposed by the OPENQUERY function – I  had to write my MDX query in 8000 characters or less! Erika and I worked out all kinds of ways to live within that constraint before we tried ASSPs, but ultimately the complexity of these queries kept pushing over the query string over the limit and thus began our adventures with ASSP. I’ll add a post on this technique to my series on Using Dynamic MDX in Reporting Services soon. (The <a href="http://blog.datainspirations.com/2010/10/07/using-dynamic-mdx-in-reporting-services-part-1/" target="_blank">first post describes the use of StrToMember() and StrToSet()</a> and <a href="http://blog.datainspirations.com/2010/10/09/using-dynamic-mdx-in-reporting-services-part-2/" target="_blank">the second post shows how to use MDX in a dynamic OLE DB query</a>.</p>
<p>I had a few extra minutes of time in my session, so I thought I’d show the audience “the rest of the story” by demonstrating how I could use the OPENQUERY function with the ASSP that I created earlier in the session. I  had the OPENQUERY working on my laptop just a few minutes before the session started, but in preparing Erika’s laptop, I didn’t think about setting up a linked server to Analysis Services in advance. No worries – I’ll just do it live! Well, my memory failed me on how to fill out the New Linked Server dialog box in Management Studio, so I asked the audience if anyone knew what to do and the reply I got was, “It’s a mystery!” (It took me a few times to realize that’s what they said – I was suffering from the “SQL plague” and my ears were really plugged up!)</p>
<p>Nothing a little search engine won’t resolve, right? Well, I turned up a few hits (like the Books Online entry <a href="http://msdn.microsoft.com/en-us/library/aa936675(SQL.80).aspx" target="_blank">Adding a Linked Server</a>), but nothing was particularly helpful for interpreting which parameters are really needed and which are optional – especially when I was on the spot! So my post today is my contribution to resolving the mystery. Of course, now that I’m offstage and working on my replaced hard drive and with a much less congested head, I was able to set up a linked server quite quickly.</p>
<p>To set up a linked server for Analysis Services, follow these steps:</p>
<ol>
<li>Connect to the Database Engine in Management Studio.</li>
<li>Expand Server Objects, right-click Linked Servers, and click New Linked Server.</li>
<li>Define a name for the linked server, and set the following options as shown in the screenshot below:</li>
</ol>
<ul>
<li>Provider: Microsoft OLE DB Provider for Analysis Services 10.0</li>
<li>Product name: MSOLAP.4</li>
<li>Data source: (the name of your server)</li>
<li>Catalog: (the name of the Analysis Services database)</li>
</ul>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/11/1f34ea158669_B9A9/image.png"><img style="background-image: none; padding-left: 0px; padding-right: 0px; display: inline; padding-top: 0px; border: 0px;" title="image" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/1f34ea158669_B9A9/image_thumb.png" border="0" alt="image" width="416" height="373" /></a></p>
<p>To test the linked server, you can write a query like this:</p>
<p><span style="font-family: 'Courier New';">select * from openquery(AdventureWorksOLAP, <span style="color: #ff0000;">&#8216;select [Measures].[Sales Amount] on columns from [Adventure Works]&#8216;</span>)</span></p>
<p>A couple of things to note &#8211; This query is executed as a database engine query, not as an MDX query. The first argument of the OPENQUERY is the name of your linked server.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2010/11/30/creating-a-linked-server-for-analysis-services/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PASS Summit 2010: Epilogue</title>
		<link>http://blog.datainspirations.com/2010/11/15/pass-summit-2010-epilogue/</link>
		<comments>http://blog.datainspirations.com/2010/11/15/pass-summit-2010-epilogue/#comments</comments>
		<pubDate>Mon, 15 Nov 2010 20:37:01 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Conference]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[PASS]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[SSRS]]></category>
		<category><![CDATA[WIT]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/2010/11/15/pass-summit-2010-epilogue/</guid>
		<description><![CDATA[Another PASS Summit has come and gone, and a good time was had by all. The song at the opening keynote sums up the experience quite nicely, &#8220;Simply the Best.&#8221; My favorite quote of the week comes from Andy Leonard (blog&#124; twitter) who tweeted on November 9, &#8220;#sqlpass is a family reunion. :{&#62;&#8221; Oddly enough, [...]]]></description>
			<content:encoded><![CDATA[<p style="margin: 0in 0in 10pt;">Another <a href="http://www.sqlpass.org/summit/na2010/" target="_blank">PASS Summit</a> has come and gone, and a good time was had by all. The song at the <a href="http://www.sqlpass.org/summit/na2010/LiveKeynotes/Tuesday.aspx" target="_blank">opening keynote</a> sums up the experience quite nicely, &#8220;Simply the Best.&#8221; My favorite quote of the week comes from Andy Leonard (<a href="http://sqlblog.com/blogs/andy_leonard" target="_blank">blog</a>| <a href="http://twitter.com/AndyLeonard" target="_blank">twitter</a>) who tweeted on November 9, &#8220;<a title="#sqlpass" href="http://twitter.com/#!/search?q=#sqlpass">#sqlpass</a> is a family reunion. :{&gt;&#8221; Oddly enough, Andy is one of the few people that I DIDN&#8217;T get to see last week, but not for lack of trying. Sorry, Andy!</p>
<p style="margin: 0in 0in 10pt;">As an independent consultant, I don&#8217;t get to interact regularly with my peers, so I love the reunion aspect of PASS. And now that I&#8217;ve started following people on Twitter, my universe of colleagues has expanded even more, and I was delighted to meet the people behind the avatars.</p>
<p style="margin: 0in 0in 10pt;">The joy of PASS is not limited to those of us who have attended for many years. As I was sitting in the airport last Friday, I recognized an attendee who was a first-timer and asked about his experience. He replied that it exceeded expectations. He was so anxious to get back to work to put what he learned into practice. He felt that the value of the knowledge that he is bringing back to the office from PASS was so much greater than the price of the conference. Now that&#8217;s a ringing endorsement if I ever heard one.</p>
<p style="margin: 0in 0in 10pt;">There is so much more that could be said about PASS, and many in the community have already posted their thoughts on Twitter and on their blogs. There has been quite a stir in the business intelligence community this past week about the future of Analysis Services, about which I will comment in a future post. Today, however, I will focus on a few follow-up comments and links to resources related to activities in which I participated last week.</p>
<p style="margin: 0in 0in 10pt;"><strong>Getting Started In Blogging And Technical Speaking</strong></p>
<p style="margin: 0in 0in 10pt;">Kendal Van Dyke (<a href="http://kendalvandyke.blogspot.com/" target="_blank">blog</a>| <a href="http://twitter.com/SQLDBA" target="_blank">twitter</a>) presented a session with tips for getting started in either of blogging or speaking. He invited a panel of experts to join him, including myself, Rob Farley (not pictured below) (<a href="http://sqlblog.com/blogs/rob_farley" target="_blank">blog</a>| <a href="http://twitter.com/rob_farley" target="_blank">twitter</a>), Aaron Bertrand (<a href="http://sqlblog.com/blogs/aaron_bertrand" target="_blank">blog</a> | <a href="http://twitter.com/AaronBertrand" target="_blank">twitter</a>), Buck Woody (<a href="http://buckwoody.com/" target="_blank">blog</a> | <a href="http://twitter.com/buckwoody" target="_blank">twitter</a>), Todd McDermid (<a href="http://toddmcdermid.blogspot.com/" target="_blank">blog</a>| <a href="http://twitter.com/Todd_McDermid" target="_blank">twitter</a>), Mike Walsh (<a href="http://www.straightpathsql.com/blog" target="_blank">blog</a> | <a href="http://twitter.com/mike_walsh" target="_blank">twitter</a>), Thomas LaRock (<a href="http://thomaslarock.com/backstage/" target="_blank">blog</a> | <a href="http://twitter.com/SQLRockstar" target="_blank">twitter</a>), Ted Krueger (<a href="http://www.lessthandot.com/" target="_blank">blog</a> | <a href="http://twitter.com/onpnt" target="_blank">twitter</a>), Patrick LeBlanc (<a href="http://sqldownsouth.blogspot.com/" target="_blank">blog</a> | <a href="http://twitter.com/patrickdba" target="_blank">twitter</a>), Andy Warren (<a href="http://www.sqlservercentral.com/blogs/andy_warren/default.aspx" target="_blank">blog</a> | <a href="http://twitter.com/sqlandy" target="_blank">twitter</a>), and Brent Ozar (<a href="http://www.brentozar.com/" target="_blank">blog</a> | <a href="http://twitter.com/BrentO" target="_blank">twitter</a>).</p>
<p style="margin: 0in 0in 10pt;">
<div id="attachment_285" class="wp-caption alignleft" style="width: 510px"><a href="http://blog.datainspirations.com/wp-content/uploads/2010/11/5168176314_fe721e07b7.jpg"><img class="size-full wp-image-285" title="Kendal Van Dyk's session at PASS Summit 2010" src="http://blog.datainspirations.com/wp-content/uploads/2010/11/5168176314_fe721e07b7.jpg" alt="" width="500" height="375" /></a><p class="wp-caption-text">Photo courtesy of Brent Ozar</p></div>
<p style="margin: 0in 0in 10pt;">Who had control of this very interactive session? You&#8217;ll have to <a href="http://www.sqlpass.org/summit/na2010/Home/OnSiteFAQ/DVDs.aspx" target="_blank">buy the PASS Summit DVD</a> to find out!</p>
<p style="margin: 0in 0in 10pt;">I waited patiently for my turn to speak. With a room full of speakers, getting your own turn can be a challenge! I heard a few attendees express concern that they didn&#8217;t know what to write about, or that someone else has covered the topic. My response to this concern is that everyone has a unique take on a topic, and that&#8217;s why T-SQL Tuesday is such a great way both to learn and to contribute. T-SQL Tuesday was started by Adam Mechanic (<a href="http://sqlblog.com/blogs/adam_machanic" target="_blank">blog</a> | <a href="http://twitter.com/AdamMachanic" target="_blank">twitter</a>) and gives everyone with an opinion (and who doesn&#8217;t have one?) or a specific experience to add to the topic. You can <a href="http://sqlblog.com/blogs/adam_machanic/archive/2009/11/30/invitation-to-participate-in-t-sql-tuesday-001-date-time-tricks.aspx" target="_blank">see the first invitation to T-SQL Tuesday here</a> to see how it all started and <a href="http://www.sqlskills.com/BLOGS/PAUL/category/T-SQL-Tuesday.aspx" target="_blank">the most recent T-SQL Tuesday posts</a> hosted by Paul Randal (<a href="http://sqlskills.com/blogs/paul/" target="_blank">blog</a> | <a href="http://twitter.com/paulrandal" target="_blank">twitter</a>). The best way to keep tabs on who&#8217;s hosting the next round is to follow the #TSQL2sDay hash tag on Twitter.</p>
<p style="margin: 0in 0in 10pt;">Unfortunately, I didn&#8217;t get to hang out for the entire presentation, because I had to move on to the…</p>
<p style="margin: 0in 0in 10pt;"><strong>Women in Technology Panel</strong></p>
<p style="margin: 0in 0in 10pt;">I was honored to participate as a panelist for this year&#8217;s Women in Technology luncheon. It was well attended, and I heard so many positive comments after the event from both men and women. I drew inspiration from my fellow panelists as well as the stories shared with me by other women attending PASS this year. You can view a recording of the event <a href="http://www.sqlpass.org/summit/na2010/LiveKeynotes/WITLuncheon.aspx" target="_blank">here</a> if you&#8217;re a registered member of PASS (which is free to join).</p>
<p style="margin: 0in 0in 10pt;">It&#8217;s so difficult to say what the right answer is for increasing the numbers of women in technology. The numbers are diminishing at a deplorable rate (<a href="http://blog.datainspirations.com/2010/07/29/maybe-its-just-me-a-perspective-from-one-woman-in-it/" target="_blank">as I discussed in a previous post</a>). It seems to me that to foster change we need to start laying the groundwork with our children. By &#8220;our children&#8221;, I mean society in general, not me specifically, although I have tried do my part! On the one hand, I don&#8217;t recommend forcing children into a career path that they can&#8217;t embrace enthusiastically. On the other hand, I believe that one reason that girls don&#8217;t pursue technology as an option is lack of exposure to the possibilities. Lynn Langit (<a href="http://blogs.msdn.com/SoCalDevGal" target="_blank">blog</a> | <a href="http://www.twitter.com/llangit" target="_blank">twitter</a>) is a role model for showing kids (not just girls!) how to explore these possibilities through <a href="http://www.teachingkidsprogramming.org/">www.teachingkidsprogramming.org</a>. Check it out!</p>
<p style="margin: 0in 0in 10pt;">Along these lines, I proposed that maybe &#8211; as great a community as PASS is &#8211; we should collectively think about what we can do for our kids. Someone tweeted that I suggested we should bring our daughters to SQLSaturday, but actually I wondered aloud if we could do something <em>similar</em> to SQLSaturday that focused on the kids (and not just girls). Maybe we could get some sponsors to help, too?</p>
<p style="margin: 0in 0in 10pt;"><strong>Demystifying MDX in Reporting Services</strong></p>
<p style="margin: 0in 0in 10pt;">In this session, I explained some of the nuances of working with MDX in Reporting Services. I have posted my demo reports <a href="http://blog.datainspirations.com/uploads/DemystifingMDXinSSRS.zip" target="_blank">here</a>.</p>
<p style="margin: 0in 0in 10pt;">In addition, you might want to refer back to some of my recent posts about using dynamic MDX in Reporting Services: <a href="http://blog.datainspirations.com/2010/10/07/using-dynamic-mdx-in-reporting-services-part-1/" target="_blank">Part 1</a> and <a href="http://blog.datainspirations.com/2010/10/09/using-dynamic-mdx-in-reporting-services-part-2/" target="_blank">Part 2</a>.</p>
<p style="margin: 0in 0in 10pt;">If you&#8217;re not familiar with MDX, I presented <a href="http://www.sqlpass.org/LearningCenter/24HoursFall.aspx" target="_blank">Session 07: Intro to MDX</a> for <a href="http://www.sqlpass.org/24hours/fall2010/" target="_blank">24 Hours of Pass: Summit Preview</a> which you can view if you have a free PASS membership. MDX is not going away any time soon, contrary to recent rumors, so invest some time learning it if you plan to work with real Analysis Services cubes, which will continue to have their place in the BI stack for several years to come.</p>
<p style="margin: 0in 0in 10pt;"><strong>Real World Analysis Services Stored Procedures</strong></p>
<p style="margin: 0in 0in 10pt;">This topic drew a larger audience than I expected as it&#8217;s a fairly specialized topic. For years, I never needed to use Analysis Services Stored Procedures (ASSP), avoiding it because folklore said so due to performance hits. However, some things just can&#8217;t be done any other way and I ran into such things this past year. To date, I haven&#8217;t found much written about ASSP other than <a href="http://msdn.microsoft.com/en-us/library/ms176113.aspx" target="_blank">BOL</a>, but you can find some <a href="http://www.codeplex.com/ASStoredProcedures" target="_blank">excellent examples to download</a> at CodePlex. Plus I&#8217;ve uploaded the <a href="http://blog.datainspirations.com/uploads/ASSP.zip" target="_blank">very simple (non-production-ready) C# example</a> that I used in my session demonstration for you to peruse.</p>
<p style="margin: 0in 0in 10pt;"><strong>What&#8217;s Next?</strong></p>
<p style="margin: 0in 0in 10pt;">So now that I&#8217;ve completed all the training and Webcasts and conference sessions that I&#8217;ve been focused on the last couple of months (with one exception &#8211; <a href="https://www2.gotomeeting.com/register/350482474" target="_blank">Delivering Information with Reporting Services</a>, a free Webcast at 12 pm Pacific on Wednesday, November 17), I plan to get back to a more regular blogging schedule. There are certainly plenty of topics on my &#8220;to do&#8221; list!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2010/11/15/pass-summit-2010-epilogue/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Dynamic MDX in Reporting Services: Part 2</title>
		<link>http://blog.datainspirations.com/2010/10/09/using-dynamic-mdx-in-reporting-services-part-2/</link>
		<comments>http://blog.datainspirations.com/2010/10/09/using-dynamic-mdx-in-reporting-services-part-2/#comments</comments>
		<pubDate>Sat, 09 Oct 2010 01:17:00 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[SSRS]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/?p=245</guid>
		<description><![CDATA[In this post, I continue my exploration of approaches to working with dynamic MDX in a Reporting Services dataset when you are using Analysis Services as a data source. I began this series with a look at string conversion functions in Part 1. In Part 1, the dynamic MDX relied on parameters that work as [...]]]></description>
			<content:encoded><![CDATA[<p>In this post, I continue my exploration of approaches to working with dynamic MDX in a Reporting Services dataset when you are using Analysis Services as a data source. I began this series with a look at <a href="http://blog.datainspirations.com/2010/10/07/using-dynamic-mdx-in-reporting-services-part-1/" target="_blank">string conversion functions in Part 1</a>. In Part 1, the dynamic MDX relied on parameters that work as a filter on the query results.</p>
<p>But what if you want to change the structure of the query itself? A parameter won&#8217;t help with that. Instead, you need to create the query string at run-time. However, the Analysis Services data source in Reporting Services doesn&#8217;t allow you to use an expression to define the query string. That&#8217;s okay- I&#8217;ll just do an end run around that problem. I&#8217;ll use an OLE DB provider to connect to my cube and then I can build up the query string by using an expression. In this post, I walk you through the process.</p>
<p>The context for this demonstration is a report that allows the user to specify the sets that appear on rows and columns of a matrix and to select one measure. It&#8217;s a very simple example that focuses on the dataset construction, and doesn&#8217;t spend as much time on the beautification of the report. Hopefully, it will give you some ideas to leverage for your own reports.</p>
<p><strong>Create a data source</strong></p>
<p>First, I need to create an OLE DB source. In the Type drop-down list, I select &#8220;OLE DB&#8221; and then I provide a connection string like this:</p>
<pre>Provider=MSOLAP.4;Data Source=.;Initial Catalog="Adventure Works DW 2008R2"</pre>
<p>The Edit button allows you to use a UI to generate the string if you don&#8217;t want to remember how to construct it manually.</p>
<p>﻿ <a href="http://blog.datainspirations.com/wp-content/uploads/2010/10/OLEDBDataSource.png"><img class="alignnone size-full wp-image-247" title="OLE DB Data Source" src="http://blog.datainspirations.com/wp-content/uploads/2010/10/OLEDBDataSource.png" alt="" width="530" height="386" /></a></p>
<p><strong>Parameters</strong></p>
<p>This set of steps is necessary to create the lists from which the user makes the selection. In my very simple example, I have created two parameters &#8211; Rows and Columns &#8211; and hard-coded possible lists. You can do more interesting things here, of course. Just make sure that the user can&#8217;t make the same selection for both parameters &#8211; whether you enforce that by manually providing the values or by doing something clever with a dynamically generated list based on a query.</p>
<p>I created the Measure parameter with the following values:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="138" valign="top"><strong>Label</strong></td>
<td width="278" valign="top"><strong>Value</strong></td>
</tr>
<tr>
<td width="138" valign="top">Sales Amount</td>
<td width="278" valign="top">=&#8221;[Measures].[Sales Amount]&#8220;</td>
</tr>
<tr>
<td width="138" valign="top">Order Quantity</td>
<td width="278" valign="top">=&#8221;[Measures].[Order Quantity]&#8220;</td>
</tr>
<tr>
<td width="138" valign="top">Gross Profit Margin</td>
<td width="278" valign="top">=&#8221;[Measures].[Gross Profit Margin]&#8220;</td>
</tr>
</tbody>
</table>
<p>I created the Columns parameters like this:</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td width="156" valign="top"><strong>Label</strong></td>
<td width="422" valign="top"><strong>Value</strong></td>
</tr>
<tr>
<td width="156" valign="top">Calendar Year</td>
<td width="422" valign="top">=&#8221;[Date].[Calendar Year].[Calendar Year].Members&#8221;</td>
</tr>
<tr>
<td width="156" valign="top">Reseller Business Type</td>
<td width="422" valign="top">=&#8221;[Reseller].[Business Type].[Business Type].Members&#8221;</td>
</tr>
</tbody>
</table>
<p>And the Rows parameters like this:</p>
<table border="1" cellspacing="0" cellpadding="0" width="751">
<tbody>
<tr>
<td width="156" valign="top"><strong>Label</strong></td>
<td width="595" valign="top"><strong>Value</strong></td>
</tr>
<tr>
<td width="156" valign="top">Product Category</td>
<td width="595" valign="top">=&#8221;[Product].[Category].[Category].Members&#8221;</td>
</tr>
<tr>
<td width="156" valign="top">Sales Territory Country</td>
<td width="595" valign="top">=&#8221;[Sales Territory].[Sales Territory Country].[Sales Territory Country].Members&#8221;</td>
</tr>
</tbody>
</table>
<p><strong>Dataset</strong></p>
<p>Although the ultimate goal is to produce a dynamic MDX query, it&#8217;s actually easier to start the design of the dataset using a static query and then to switch it out later. By using a static query, the fields for the dataset are autogenerated. The less work I have to do, the better.</p>
<p>Now one thing about dynamic MDX in Reporting Services is the need to make sure the number of fields in the dataset are the same each and every time. Therefore I need to structure the query differently than I would if I were to write it for a &#8220;normal&#8221; Analysis Services client. That is, I need to rewrite a query like this:</p>
<pre>select</pre>
<pre>non empty [Date].[Calendar Year].[Calendar Year].Members on columns,</pre>
<pre>non empty [Product].[Category].[Category].Members on rows</pre>
<pre>from [Adventure Works]</pre>
<pre>where [Measures].[Sales Amount]</pre>
<div>which produces a result like this:</div>
<div><a href="http://blog.datainspirations.com/wp-content/uploads/2010/10/StandardQueryResults.png"><img class="alignnone size-full wp-image-250" title="Standard Query Results" src="http://blog.datainspirations.com/wp-content/uploads/2010/10/StandardQueryResults.png" alt="" width="447" height="97" /></a></div>
<div>to a query that looks like this:</div>
<div>
<pre>select</pre>
</div>
<pre>
<div id="_mcePaste">[Measures].[Sales Amount] on columns,</div>
<div id="_mcePaste">non empty</div>
<div id="_mcePaste">([Product].[Category].[Category].Members,</div>
<div id="_mcePaste">[Date].[Calendar Year].[Calendar Year].Members)</div>
<div id="_mcePaste">on rows</div>
<div id="_mcePaste">from [Adventure Works]</div>
</pre>
<p>and produces a result like this:</p>
<div><a href="http://blog.datainspirations.com/wp-content/uploads/2010/10/ModifiedQueryResults.png"><img class="alignnone size-full wp-image-251" title="Modified Query Results" src="http://blog.datainspirations.com/wp-content/uploads/2010/10/ModifiedQueryResults.png" alt="" width="246" height="237" /></a></div>
<div>However, while structurally the result set is what I need, the fields generated for the dimensions above will change each time that I run the dynamic query with different specifications for rows and columns. So I need to modify the query one more time like this:</div>
<pre>
<div>with</div>
<div>member [Measures].[Measure] as [Measures].[Sales Amount]</div>
<div>member [Measures].[RowValue] as [Product].[Category].CurrentMember.Name</div>
<div>member [Measures].[ColumnValue] as [Date].[Calendar Year].CurrentMember.Name</div>
<div>select {[Measures].[Measure], [Measures].[RowValue], [Measures].[ColumnValue]} on columns,</div>
<div>non empty ([Product].[Category].[Category].Members, [Date].[Calendar Year].[Calendar Year].Members) on rows</div>
<div>from [Adventure Works]</div>
</pre>
<p>To get a result like this:</p>
<div><a href="http://blog.datainspirations.com/wp-content/uploads/2010/10/FinalModifiedQueryResults3.png"><img class="alignnone size-full wp-image-257" title="Final Modified Query Results" src="http://blog.datainspirations.com/wp-content/uploads/2010/10/FinalModifiedQueryResults3.png" alt="" width="704" height="158" /></a></div>
<div>Now I can reference the generic Measure, RowValue, and ColumnValue in the report layout.</div>
<p><strong>Matrix</strong></p>
<p>I like to test things out before I start introducing more complexity. So my next step is to add a matrix layout to the report design, and put fields into the layout and apply a little formatting as shown below.</p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/10/MatrixLayout1.png"><img class="alignnone size-full wp-image-258" title="Matrix Layout" src="http://blog.datainspirations.com/wp-content/uploads/2010/10/MatrixLayout1.png" alt="" width="357" height="73" /></a></p>
<p>One extra step related to formatting is required in my example. I have three possible measures, each of which uses a different format string. If I were displaying detail records, I could use the formatted_value cell property as an extended property in the textbox expression, replacing Fields!Measure.Value with Fields!Measure.FormattedValue. However, the use of a matrix here doesn&#8217;t work with that approach, so&#8230; I need to create a conditional expression to set the Format property correctly:</p>
<pre>=Switch(Parameters!Measure.Label = "Sales Amount", "C2", Parameters!Measure.Label = "Order Quantity", "N0",</pre>
<pre>Parameters!Measure.Label = "Gross Profit Margin", "P2")</pre>
<p>Then I preview the report to make sure all is well, which it is.</p>
<p><strong>Query expression &#8211; step 1</strong></p>
<p>Now it&#8217;s time to do the deed &#8211; convert the query string to an expression. To do this, I open Dataset Properties and click the expression button (fx) next to the Query box.</p>
<p>The first step is just to enclose the query in double-quotes and prefix with an equal sign and to eliminate all the line feeds in the query. The expression needs to be one long string. If you really must add line feeds to make it easier to read, you can set up the expression like this:</p>
<pre>="with"</pre>
<pre>+ " member [Measures].[Measure] as [Measures].[Sales Amount]"</pre>
<pre>+ " member [Measures].[RowValue] as [Product].[Category].CurrentMember.Name"</pre>
<pre>+ " member [Measures].[ColumnValue] as [Date].[Calendar Year].CurrentMember.Name"</pre>
<pre>+ " select {[Measures].[Measure], [Measures].[RowValue], [Measures].[ColumnValue]} on columns,"</pre>
<pre>+ " non  empty ([Product].[Category].[Category].Members, [Date].[Calendar Year].[Calendar Year].Members) on rows"</pre>
<pre>+ " from [Adventure Works]"</pre>
<p>Just make sure to allow for a space between words on separate lines. I put it at the beginning of each new line so that I can see it easily. I then preview the report again to make sure that the expression works before I add in the next layer of complexity.</p>
<p><strong>Query expression &#8211; step 2</strong></p>
<p>Next I plug in parameter values in the appropriate sections of the query, like this:</p>
<pre>="with"
+ " member [Measures].[Measure] as " + Parameters!Measure.Value
+ " member [Measures].[RowValue] as"
+ " " + Split(Parameters!Rows.Value,"]")(0) + "]" + Split(Parameters!Rows.Value,"]")(1)+ "].CurrentMember.Name"
+ " member [Measures].[ColumnValue] as"
+ " " + Split(Parameters!Columns.Value,"]")(0) + "]"
+ Split(Parameters!Columns.Value,"]")(1)+ "].CurrentMember.Name"
+ " select {[Measures].[Measure], [Measures].[RowValue], [Measures].[ColumnValue]} on columns,"
+ " non  empty (" + Parameters!Rows.Value + ", " + Parameters!Columns.Value + ") on rows"
+ " from [Adventure Works]"</pre>
<p>Then I preview again. Here&#8217;s the report with the default parameter settings: products on rows, dates on columns, and sales amount as the measure.</p>
<p><a href="http://blog.datainspirations.com/wp-content/uploads/2010/10/DefaultParameterValues.png"><img class="alignnone size-full wp-image-259" title="Default Parameter Values" src="http://blog.datainspirations.com/wp-content/uploads/2010/10/DefaultParameterValues.png" alt="" width="750" height="97" /></a></p>
<p>And here&#8217;s the report with sales territory on rows, business type on columns, and gross profit margin as the measure.<br />
<a href="http://blog.datainspirations.com/wp-content/uploads/2010/10/ModifiedParameterValues.png"><img class="alignnone size-full wp-image-260" title="Modified Parameter Values" src="http://blog.datainspirations.com/wp-content/uploads/2010/10/ModifiedParameterValues.png" alt="" width="499" height="145" /></a></p>
<p>Mission accomplished!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2010/10/09/using-dynamic-mdx-in-reporting-services-part-2/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Using Dynamic MDX in Reporting Services: Part 1</title>
		<link>http://blog.datainspirations.com/2010/10/07/using-dynamic-mdx-in-reporting-services-part-1/</link>
		<comments>http://blog.datainspirations.com/2010/10/07/using-dynamic-mdx-in-reporting-services-part-1/#comments</comments>
		<pubDate>Thu, 07 Oct 2010 16:27:00 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[SSRS]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/2010/10/07/using-dynamic-mdx-in-reporting-services-part-1/</guid>
		<description><![CDATA[If you&#8217;re using Analysis Services as a data source for Reporting Services reports, you can build a simple dataset using the graphical query designer, but you&#8217;ll want to switch to the generic query designer to create the MDX query string manually when you have more advanced requirements. Using the generic query designer, you can: · [...]]]></description>
			<content:encoded><![CDATA[<p style="MARGIN: 0in 0in 10pt">If you&#8217;re using Analysis Services as a data source for Reporting Services reports, you can build a simple dataset using the graphical query designer, but you&#8217;ll want to switch to the generic query designer to create the MDX query string manually when you have more advanced requirements. Using the generic query designer, you can:</p>
<p style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 38.25pt; mso-add-space: auto; mso-list: l0 level1 lfo1">· Impose greater control over the sets that you want to add to the rows axis by using set functions.</p>
<p style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 0pt 38.25pt; mso-add-space: auto; mso-list: l0 level1 lfo1">· Add query-scoped named sets to the query in addition to calculated members. (Calculated members can also be added in the graphical query designer, but not named sets.)</p>
<p style="TEXT-INDENT: -0.25in; MARGIN: 0in 0in 10pt 38.25pt; mso-add-space: auto; mso-list: l0 level1 lfo1">· Build dynamic MDX queries.</p>
<p style="MARGIN: 0in 0in 10pt">When would you need a dynamic MDX query? Whenever you want to modify the query based on a condition known only at run-time, typically based on a parameter value. If you&#8217;re using the graphical query designer, you can auto-generate the report parameter&#8217;s query for available values by selecting the Parameter checkbox. When the user selects a value during report execution, Reporting Services passes the unique name for the selection to the query and all is well. However, there might be situations when the user selection doesn&#8217;t come from the cube, so you must find a way to convert the parameter value into a value that will work with the query.</p>
<p style="MARGIN: 0in 0in 10pt">In a series of posts, I will explore the available options for working with dynamic MDX queries in Reporting Services. By dynamic MDX, I mean that the query can be different each time it executes. In this post, I cover the use of <a href="http://technet.microsoft.com/en-us/library/ms146022.aspx" target="_blank">StrToMember()</a> and <a href="http://technet.microsoft.com/en-us/library/ms144782.aspx" target="_blank">StrToSet()</a> functions in parameters.</p>
<p style="MARGIN: 0in 0in 10pt">A very common scenario is the requirement to pass dates into a query. If you have a date filter for the report, do you really want users to navigate through a list of dates from the cube as shown below?</p>
<p style="MARGIN: 0in 0in 10pt"><img src="http://Blog.datainspirations.com/wp-content/uploads/2010/10/DateParameterList.png" style="WIDTH: 177px; DISPLAY: inline; HEIGHT: 212px" height="212" alt="Date Parameter List" width="177"/></p>
<p style="MARGIN: 0in 0in 10pt">This list of dates &#8211; even if it&#8217;s arranged hierarchically by month, quarter, and year &#8211; is what you get when you build the parameter directly from the date hierarchy in the query designer as shown below.</p>
<p style="MARGIN: 0in 0in 10pt"><img src="http://blog.datainspirations.com/wp-content/uploads/2010/10/GraphicalQueryDesigner.png" style="WIDTH: 624px; DISPLAY: inline; HEIGHT: 243px" height="243" alt="Graphical Query Designer" width="624"/></p>
<p style="MARGIN: 0in 0in 10pt">Wouldn&#8217;t a more user-friendly experience allow the user to select a data from a calendar control? I can do this by changing the auto-generated report parameter&#8217;s data type to a Date/Time data type and clear the &#8220;Allow multiple values&#8221; check box. I must also change the Available Values setting for the parameter to None. I can set the default value to &#8220;No default value&#8221; to force the user to make a selection, or do something nice like define an expression to set a date, like =Today().</p>
<p style="MARGIN: 0in 0in 10pt">So far, so good. But the problem now is that the date data type returned by the calendar control cannot be used by the MDX query without some intervention. I need to change the Parameter Value mapped to the query parameter in the Dataset Properties to an expression, like this:</p>
<p style="MARGIN: 0in 0in 10pt">=&#8221;[Date].[Calendar].[Date].[" + Format(CDate(Parameters!DateCalendar.Value), "MMMM d, yyyy") + "]&#8220;</p>
<p style="MARGIN: 0in 0in 10pt">
<p style="MARGIN: 0in 0in 10pt"><img src="http://blog.datainspirations.com/wp-content/uploads/2010/10/DataSetProperties.png" style="WIDTH: 624px; DISPLAY: inline; HEIGHT: 246px" height="246" alt="" width="624"/></p>
<p style="MARGIN: 0in 0in 10pt">The expression that you use to convert a date like 2/1/2008 to a valid unique name in your Date dimension might look different. My example is specific to the Adventure Works 2008 R2 cube, which requires the date member to look like this: [Date].[Calendar].[Date].[February 1, 2008].</p>
<p style="MARGIN: 0in 0in 10pt">That&#8217;s fine so far, but the result of this expression is a string and the MDX query requires a member or a set. The autogenerated query already makes this change for you fortunately. However, if you&#8217;re creating your query manually, you should understand what it&#8217;s doing, especially if you need to make changes to it.</p>
<p style="MARGIN: 0in 0in 10pt">The autogenerated query looks like this before I make changes:</p>
<pre>
SELECT NON EMPTY { [Measures].[Sales Amount] } ON COLUMNS,
NON EMPTY { ([Product].[Category].[Category].ALLMEMBERS ) }
DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME ON ROWS
FROM ( SELECT ( STRTOSET(@DateCalendar, CONSTRAINED) ) ON COLUMNS
FROM [Adventure Works])
<span style="COLOR: #ff0000">WHERE ( IIF( STRTOSET(@DateCalendar, CONSTRAINED).Count = 1, <br/>STRTOSET(@DateCalendar, CONSTRAINED), [Date].[Calendar].currentmember ) ) <br/>CELL PROPERTIES VALUE, BACK_COLOR, FORE_COLOR, FORMATTED_VALUE, FORMAT_STRING, FONT_NAME, FONT_SIZE, FONT_FLAGS</span>
</pre>
<p style="MARGIN: 0in 0in 10pt">I prefer to simplify the query as shown below &#8211; removing the text highlighted in red text above. The function does what it says &#8211; changes the string (represented by the parameter @DateCalendar) into a set object. I remove the WHERE clause from the query as the FROM clause adequately restricts the query results to cell values related to the selected date. If I need the dimension properties in the report to display something or if I need the cell properties for report formatting, I&#8217;ll include only the ones I need, but for this example I have removed them all from the query.</p>
<pre>
SELECT NON EMPTY { [Measures].[Sales Amount] } ON COLUMNS,
NON EMPTY { ([Product].[Category].[Category].ALLMEMBERS ) } ON ROWS
FROM ( SELECT ( STRTOSET(@DateCalendar, CONSTRAINED) ) ON COLUMNS
FROM [Adventure Works])
</pre>
<p style="MARGIN: 0in 0in 10pt">You could change the StrToSet() function to a StrToMember() function and get the same result. It&#8217;s not harmful to leave StrToSet() as it is. It just returns a set of one member in this case-the date from the calendar control which is a valid set. The CONSTRAINED flag is used to prevent an injection attack and requires the expression to resolve to a valid member before the query executes.</p>
<p style="MARGIN: 0in 0in 10pt">One challenge that often confounds people working with MDX queries in the generic query designer is the inability to copy and paste the query into Management Studio for testing when parameters are in the query as shown above. The MDX query editor doesn&#8217;t support parameters. Teo Lachev (<a href="http://prologika.com/cs/blogs" target="_blank">blog</a> | <a href="http://twitter.com/tlachev" target="_blank">twitter</a>) posted <a href="http://prologika.com/CS/blogs/blog/archive/2009/07/06/how-to-test-ssrs-mdx-queries-in-sql-server-management-studio.aspx" target="_blank" title="How to Test SSRS MDX Queries in SQL Server Management Studio">some advice for working with parameterized MDX queries in Management Studio</a> which I encourage you to check out.</p>
<p style="MARGIN: 0in 0in 10pt">In my next post, I&#8217;ll explain how to use the OLE DB for OLAP provider with dynamic MDX to create a dataset.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2010/10/07/using-dynamic-mdx-in-reporting-services-part-1/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>24 Hours of Pass Summit Preview: Introduction to MDX</title>
		<link>http://blog.datainspirations.com/2010/09/15/24-hours-of-pass-summit-preview-introduction-to-mdx/</link>
		<comments>http://blog.datainspirations.com/2010/09/15/24-hours-of-pass-summit-preview-introduction-to-mdx/#comments</comments>
		<pubDate>Wed, 15 Sep 2010 23:15:59 +0000</pubDate>
		<dc:creator>Stacia Misner</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[PASS]]></category>
		<category><![CDATA[SSAS]]></category>

		<guid isPermaLink="false">http://blog.datainspirations.com/2010/09/15/24-hours-of-pass-summit-preview-introduction-to-mdx/</guid>
		<description><![CDATA[Many thanks to everyone who attended my session today, Introduction to MDX. There was so much more I wanted to say, but the constraint of an hour required me to be very selective and, as you might have noticed, to sacrifice the demos. After all, how exciting can it be to watch me execute a [...]]]></description>
			<content:encoded><![CDATA[<p>Many thanks to everyone who attended my session today, Introduction to MDX. There was so much more I wanted to say, but the constraint of an hour required me to be very selective and, as you might have noticed, to sacrifice the demos. After all, how exciting can it be to watch me execute a query? I thought it more important to provide you with the key concepts that you can use to get started.</p>
<p>When I first learned MDX, I didn&#8217;t learn it the way that I explained it today. Consequently, I struggled for a long time until the proverbial light bulb turned on in my head about how to think about the language. I hope that my explanation saves you some of the grief that I experienced, although I can&#8217;t promise that you aren&#8217;t going to have (and lose) a few wrestling matches as you build up your MDX muscles.</p>
<p>As promised, I have sample queries that illustrate the concepts that I discussed today. Before you can run the queries, I assume that you have both a SQL Server 2008 R2 database instance and an Analysis Services instance. You will need to download and install the <a style="color: #072c62; text-decoration: none;" title="AdventureWorks 2008R2 RTM Data Product Samples" href="http://msftdbprodsamples.codeplex.com/releases/view/45907" target="_blank"><span style="text-decoration: underline;">AdventureWorks 2008 R2 sample database</span></a>. Then open the Intro to MDX solution included in the zip file and deploy the project to create the simple cube for the queries. Then open the MDX files in SQL Server Management Studio. You can run the entire script, and thereby execute multiple queries, or run one at a time by highlighting the query text as described in the header of each MDX file. These queries and the SSAS solution might work with earlier versions of SQL Server, but is untested.</p>
<p>Download the zip file containing the queries and SSAS solution <span style="text-decoration: underline;"><a title="Introduction to MDX sample files" href="http://datainspirations.com/uploads/IntroToMDX.zip" target="_blank">here</a></span>.</p>
<p>If you plan to attend the <span style="text-decoration: underline;"><a href="http://www.sqlpass.org/summit/na2010/" target="_blank">PASS Summit 2010</a></span> in Seattle, be sure to see my session, <a href="http://sqlpass.eventpoint.com/topic/details/BID218" target="_blank">Demystifying MDX in Reporting Services</a>, where I explain how to use MDX with Reporting Services. There are a few differences from the query structure that I described today that you&#8217;ll need to know.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.datainspirations.com/2010/09/15/24-hours-of-pass-summit-preview-introduction-to-mdx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

