<?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>The Frog-Blog &#187; Analysis Services</title>
	<atom:link href="http://www.purplefrogsystems.com/blog/index.php/category/analysis-services/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.purplefrogsystems.com/blog</link>
	<description>Purple Frog-Blog for all that is Business Intelligence</description>
	<lastBuildDate>Fri, 03 Sep 2010 14:36:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Will DAX replace MDX</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2010/09/will-dax-replace-mdx/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2010/09/will-dax-replace-mdx/#comments</comments>
		<pubDate>Fri, 03 Sep 2010 14:36:33 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[PowerPivot]]></category>
		<category><![CDATA[DAX]]></category>
		<category><![CDATA[MDX]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=165</guid>
		<description><![CDATA[For those that haven&#8217;t yet heard of DAX, it&#8217;s an expression language developed by Microsoft to perform calculations against PowerPivot. Stepping back one step further, PowerPivot is essentially a local Analysis Services cube that runs within Excel 2010.
I&#8217;ve heard plenty of comments from various sources about how DAX is the [multi-dimensional] query language of the [...]]]></description>
			<content:encoded><![CDATA[<p>For those that haven&#8217;t yet heard of DAX, it&#8217;s an expression language developed by Microsoft to perform calculations against PowerPivot. Stepping back one step further, PowerPivot is essentially a local Analysis Services cube that runs within Excel 2010.</p>
<p>I&#8217;ve heard plenty of comments from various sources about how DAX is the [multi-dimensional] query language of the future and how it&#8217;s going to kill off MDX. Ok&#8230;. well no, it&#8217;s not ok.</p>
<p>For starters they both exist for two different purposes. DAX is not a query language but an expression language. You can use MDX to query information from a cube and generate a pivot, you can&#8217;t with DAX as it is not a query language.</p>
<p><img class="size-full wp-image-166 alignleft" title="powerpivot" src="http://www.purplefrogsystems.com/blog/wp-content/uploads/2010/09/powerpivot.jpg" alt="" width="110" height="111" />The best way to think of DAX is as an extension to Excel formulas, you can use it to perform a calculation against an existing set of cells, in this case, a PowerPivot dataset.</p>
<p>It is also similar to an MDX calculated member, and in fact supports a number of MDX functions (TotalYTD, ParallelPeriod etc.).</p>
<p><strong>If your data is in a database:</strong> You would use SQL to query data from a database and import the results into Excel. You would then use Excel expressions/calculations to enhance the data.</p>
<p><strong>If your data is in a cube:</strong> You would use an Excel pivot (or MDX query) to query the data and import the results into Excel. You then have to use a third party tool such as <a href="http://olappivottableextend.codeplex.com/" target="_blank">OLAP PivotTable Extensions</a> to add expressions/calculations to enhance the data.</p>
<p><strong>If your data is in PowerPivot:</strong> You would use PowerPivot to query the data and import the results into Excel. You would then use DAX to add calculations to enhance the data.</p>
<p>DAX is a fantastic expression tool, and one that provides significant power to PowerPivot, but no, it won&#8217;t replace MDX. My hope is that Microsoft will provide DAX capability for MDX queries as well, and not restrict it to PowerPivot queries. As I&#8217;ve shown in my previous blog post it&#8217;s a great expression language that would provide significant benefit to cube users.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2010/09/will-dax-replace-mdx/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Calculate Run Rate (Full Year Projection) in MDX</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2010/08/calculate-run-rate-full-year-projection-in-mdx/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2010/08/calculate-run-rate-full-year-projection-in-mdx/#comments</comments>
		<pubDate>Wed, 18 Aug 2010 17:26:18 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Calculated Member]]></category>
		<category><![CDATA[Cube]]></category>
		<category><![CDATA[Finance]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[OLAP]]></category>
		<category><![CDATA[SSAS]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=152</guid>
		<description><![CDATA[This post explains how to create an MDX calculated member that will take a value from the cube and project it forward to the end of the year. This provides a simple mechanism for calculating what your expected total will be at year end, based upon current performance.
To do this more accurately you should use [...]]]></description>
			<content:encoded><![CDATA[<p>This post explains how to create an MDX calculated member that will take a value from the cube and project it forward to the end of the year. This provides a simple mechanism for calculating what your expected total will be at year end, based upon current performance.</p>
<p>To do this more accurately you should use time series data mining models in SSAS and use DMX expressions to query the results, but this method is very simple and requires little effort, and will be pretty accurate so long as the data you&#8217;re modelling is fairly linear. Please note though that the more cyclical and seasonal your data is the less effective this will be.</p>
<p>The basic idea is that we take what we have done so far (i.e. year to date sales), look at how far through the year we are, and extrapolate the value of future months (or days/weeks/etc.) based upon values so far.</p>
<p>i.e. If we&#8217;re at March month end and we&#8217;ve sold 100 widgets so far this year, we&#8217;re 1/4 of the way through the year so we multiply 100 by 4 and get a prejected yearly total of 400.</p>
<p><img src="http://www.purplefrogsystems.com/blog/wp-content/uploads/2010/08/RunRateAt6Months.png" alt="" title="RunRateAt6Months" width="462" height="220" class="alignleft size-full wp-image-153" /><br />
This chart shows the concept of what we&#8217;re doing, and shows the full year prejections calculated in March (with 3 months of available data) and June (6 months of data). The projections obviously get more accurate the further you are through the year.</p>
<p>One of the points to note is that when creating a calculation like this, based upon a time dimension, the calculation should always work with any level of the dimension hierarchy selected. i.e. The user shouldn&#8217;t care whether they&#8217;re looking at a month, week, quarter or a day, the calculation should always work the same. To achieve this we simply use the .currentmember of the time hierarchy.</p>
<p>The following examples are based upon projecting the Internet Sales Amount measure found within the SQL Server 2008 Adventure Works DW sample cube.</p>
<p><b>Step 1 &#8211; What are our total sales so far this year?</b></p>
<p>MDX helpfully provides us with the YTD function which takes care of this for us.</p>
<pre><span style="color: #008000;">
  MEMBER [Measures].[YTD Sales] AS
    AGGREGATE(
      YTD([Date].[Calendar].CurrentMember)
      ,[Measures].[Internet Sales Amount])
</span></pre>
<p>This takes the current member of the Calendar hierarchy, and creates a set of all dates before it (this year) using YTD. It then aggregates (in this case sums) the Internet Sales Amount for all of these dates to calculate YTD Sales.</p>
<p><b>Step 2 &#8211; Which period are we in?</b></p>
<p>Here we&#8217;ll use the same YTD function to create a set of all dates so far this year, but in this case we&#8217;ll count the number of resulting members. Note that because we&#8217;re using the .CurrentMember of the hierarchy, it doesn&#8217;t matter if we&#8217;re looking at a date, week or month, the MDX will work. i.e. If we&#8217;re looking at 21 Jan it will return 21. If we&#8217;re looking at Q3 it will return 3, August will return 8 etc.</p>
<pre><span style="color: #008000;">
  MEMBER [Measures].[CurPeriod] AS
    COUNT(
      YTD([Date].[Calendar].CurrentMember)
      ,INCLUDEEMPTY)
</span></pre>
<p><b>Step 3 &#8211; How many periods are in the year?</b></p>
<p>If we coded this to only work with months then we could hard code this to 12 however we need to keep it generic to all levels of the hierarchy. So, we have to count all the cousins of the current time member [within this year]. Unfortunately there isn&#8217;t a Cousins function in MDX, and Siblings will only return other members within the same parent. i.e. siblings of May 4th would include May 1 through to May 31. To get around this we find the year of the current member by using the Ancestor function.</p>
<pre><span style="color: #008000;">
  ANCESTOR([Date].[Calendar].CurrentMember
  , [Date].[Calendar].[Calendar Year])
</span></pre>
<p>Then we find all of the descendants of the year, at the same level of the hierarchy (week/day/etc.) as the current member. We can then take a count as before.</p>
<pre><span style="color: #008000;">
  MEMBER [Measures].[TotalPeriods] AS
    COUNT(
      DESCENDANTS(
        ANCESTOR([Date].[Calendar].CurrentMember
          ,[Date].[Calendar].[Calendar Year])
        ,[Date].[Calendar].CurrentMember.level)
      ,INCLUDEEMPTY)
</span></pre>
<p><b>Step 4 &#8211; Calculate the Run Rate</b></p>
<p>Calculating the prejected yearly total (run rate) is then a simple calculation</p>
<pre><span style="color: #008000;">
  MEMBER [Measures].[Full Year Run Rate] AS
    [Measures].[YTD Sales]
    * ([Measures].[TotalPeriods]
       /[Measures].[CurPeriod])
</span></pre>
<p>You can then put the whole lot together and see the results&#8230;</p>
<pre><span style="color: #008000;">
WITH

  MEMBER [Measures].[YTD Sales] AS
    AGGREGATE(
      YTD([Date].[Calendar].CurrentMember)
      ,[Measures].[Internet Sales Amount])

  MEMBER [Measures].[CurPeriod] AS
    COUNT(
      YTD([Date].[Calendar].CurrentMember)
      ,INCLUDEEMPTY)

  MEMBER [Measures].[TotalPeriods] AS
    COUNT(
      DESCENDANTS(
        ANCESTOR([Date].[Calendar].CurrentMember
          ,[Date].[Calendar].[Calendar Year])
        ,[Date].[Calendar].CurrentMember.level)
      ,INCLUDEEMPTY)

  MEMBER [Measures].[Full Year Run Rate] AS
    [Measures].[YTD Sales]
    * ([Measures].[TotalPeriods]
       /[Measures].[CurPeriod])

SELECT
{
     [Measures].[Internet Sales Amount]
    ,[Measures].[YTD Sales]
    ,[Measures].[Full Year Run Rate]
    ,[Measures].[CurPeriod]
    ,[Measures].[TotalPeriods]
} ON 0,
{
    DESCENDANTS([Date].[Calendar].[CY 2003])
} ON 1
FROM [Direct Sales]
</span></pre>
<p>In my next blog I&#8217;ll be diong the same calculation in DAX for use with PowerPivot, stay tuned&#8230;</p>
<p>Frog-Blog Out</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2010/08/calculate-run-rate-full-year-projection-in-mdx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MDX Calculated Member Spanning Multiple Date Dimensions</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2010/08/mdx-calculated-member-spanning-multiple-date-dimensions/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2010/08/mdx-calculated-member-spanning-multiple-date-dimensions/#comments</comments>
		<pubDate>Thu, 05 Aug 2010 17:09:51 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Calculated Member]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[Semi Additive]]></category>
		<category><![CDATA[SSAS]]></category>
		<category><![CDATA[Time Dimension]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=140</guid>
		<description><![CDATA[It’s common in most cubes to have a number of different date dimensions, whether role playing, distinct, or a combination of both. Say for example, Entry Date, Posting Date and Accounting Period. There may also be numerous hierarchies in each date dimension, such as calendar and fiscal calendar, leading to a relatively complicated array of [...]]]></description>
			<content:encoded><![CDATA[<p>It’s common in most cubes to have a number of different date dimensions, whether role playing, distinct, or a combination of both. Say for example, Entry Date, Posting Date and Accounting Period. There may also be numerous hierarchies in each date dimension, such as calendar and fiscal calendar, leading to a relatively complicated array of dates to worry about when calculating semi-additive measures.</p>
<p>If we create a date related calculation (i.e. total to date) how do we ensure that this calculation works across all date dimensions?</p>
<p>Lets assume we have a stock movement measure, where each record in the fact table is the change in stock (plus or minus). The current stock level is found by using a calculation totaling every record to date.</p>
<pre><span style="color: #008000;">CREATE MEMBER CURRENTCUBE.[Measures].[Stock Level]
AS
  SUM({NULL:[Date].[Calendar].CurrentMember}
     , [Measures].[Stock Movement]
  );
</span></pre>
<p>[Note that {NULL:xxx} just creates a set of everything before the xxx member, i.e. everything to date]</p>
<p>This works just fine, if the user selects the [Date].[Calendar] hierarchy. What if the user selects the [Date].[Fiscal] hierarchy, or the [Period] dimension? Basically the calculation wont work, as the MDX expression is only aware of the [Date].[Calendar] hierarchy.</p>
<p>The simple solution is to use the Aggregate function over all of the dimensions that the calculation needs to be aware of:</p>
<pre><span style="color: #008000;">CREATE MEMBER CURRENTCUBE.[Measures].[Stock Level]
AS
  AGGREGATE(
      {NULL:[Date].[Fiscal].CurrentMember}
       * {NULL:[Date].[Calendar].CurrentMember}
       * {NULL:[Period].[Period].CurrentMember}
    , [Measures].[Stock Movement]
  );
</span></pre>
<p>The calculation will then use whichever date or time hierarchy is selected. It will even cope if multiple dimensions are selected, say the calendar on 0 and the periods on 1, both axis will honor the aggregation as expected.</p>
<p>Frog-Blog out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2010/08/mdx-calculated-member-spanning-multiple-date-dimensions/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL User Group Session 24 June 2010</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2010/06/sql-user-group-session-24-june-2010/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2010/06/sql-user-group-session-24-june-2010/#comments</comments>
		<pubDate>Wed, 09 Jun 2010 20:01:53 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Data Warehouse]]></category>
		<category><![CDATA[Modelling]]></category>
		<category><![CDATA[Star Schema]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=117</guid>
		<description><![CDATA[I&#8217;m excited to be presenting another session to the South Wales SQL Server User Group.
On Thursday 24th June 2010, Eversheds in Cardiff are kindly hosting the event, to run from 18:45 to 21:00.
The event is free, and you&#8217;ll even get pizza thrown in &#8211; what more can you ask for? Oh yes, some BI content&#8230;
My [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m excited to be presenting another session to the South Wales SQL Server User Group.</p>
<p>On Thursday 24th June 2010, Eversheds in Cardiff are kindly hosting the event, to run from 18:45 to 21:00.<br />
The event is free, and you&#8217;ll even get pizza thrown in &#8211; what more can you ask for? Oh yes, some BI content&#8230;</p>
<p>My session will cover data warehouse modelling, including a number of hands on business case studies including transactional data, account balances and duration based data.</p>
<p>Please feel free to bring your own data modelling problems along and I&#8217;ll try and cover as many as I can.</p>
<p>Register for free here: <a href="http://www.sqlserverfaq.com/events/235/Data-warehouse-design-case-studies-Other-BI-related-session-TBC.aspx" target="_blank">http://www.sqlserverfaq.com/events/235/Data-warehouse-design-case-studies-Other-BI-related-session-TBC.aspx</a></p>
<p>Hope to see you there!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2010/06/sql-user-group-session-24-june-2010/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SQL Server 2008 R2 &#8211; PowerPivot and Master Data Services</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2010/05/sql-server-2008-r2-powerpivot-and-master-data-services/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2010/05/sql-server-2008-r2-powerpivot-and-master-data-services/#comments</comments>
		<pubDate>Tue, 18 May 2010 20:13:48 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Integration Services]]></category>
		<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[DAX]]></category>
		<category><![CDATA[Master Data Services]]></category>
		<category><![CDATA[PowerPivot]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=114</guid>
		<description><![CDATA[Purple Frog spent a very interesting day at Microsoft last week, at one of their many events promoting the launch of SQL Server 2008 R2. Rafal Lukewiecki presented an entertaining (as always!) and informative series of talks covering the release, focusing on the enhanced Business Intelligence tools available.
The primary changes to note are

Power Pivot – [...]]]></description>
			<content:encoded><![CDATA[<p>Purple Frog spent a very interesting day at Microsoft last week, at one of their many events promoting the launch of SQL Server 2008 R2. Rafal Lukewiecki presented an entertaining (as always!) and informative series of talks covering the release, focusing on the enhanced Business Intelligence tools available.</p>
<p>The primary changes to note are</p>
<ul>
<li><strong>Power Pivot</strong> – An in memory, client side add-in to Excel, that allows users to create virtual cubes on their desktop and analyse over 100m records of data virtually instantly</li>
<li><strong>DAX </strong>– A new expression language, designed for non-technical (probably more realistically, semi-technical) users to extend pivot tables and power pivot tables without having to learn MDX</li>
<li><strong>Report Components</strong> – In a report consisting of a couple of tables, a chart and a few gauges (gauges, sparklines &amp; maps are all new features of SSRS), you can save each element as a component and re-use it in different reports. This should result in much less duplication of work.</li>
<li><strong>Report Builder 3</strong> – A thin-client tool allowing end users to create Reporting Services reports. This is a big enhancement over its predecessor s it is finally fully compatible with reports created in the Business Intelligence Development Studio (BIDS), including report components.</li>
<li><strong>Master Data Services</strong> – A centralised tool and database intended to provide governance of your organisation’s master data (centralised list of products, fiscal calendar, regions etc.).</li>
</ul>
<p>The enhancements to <strong>Reporting Services</strong> (SSRS) are very welcome, and should be of huge benefit to anyone either currently using SSRS or considering using it. I firmly believe that there are no comparable web based reporting engines that even come close for SME organisations when looking at the whole picture including cost of implementation, ease of use, flexibility and capability.</p>
<p><strong>Master Data Services</strong> as a concept has been around for a long time, but there has never been a tool available to organisations to effectively implement it. This is Microsoft’s first proper stab at delivering a workable solution, and although I’m a big fan of the concept, and have no doubt of its benefit to a SME, I’m yet to be convinced that the tool is ready for a large scale corporate environment. Time will tell how scalable and manageable the system is, and credit has to go to Microsoft for starting the ball rolling.</p>
<p>The most impressive addition is without a doubt <strong>PowerPivot</strong>. In a nutshell, it’s a user defined OLAP cube wrapped up within Excel 2010, running entirely in memory on a user’s workstation. If you’ve not yet played with it or seen a demo, I’ll try and elaborate for you… Think about loading Excel with 1 million rows, and then imagine sorting and filtering a number of those columns [cue going out to lunch whilst waiting for Excel to catch up]. With PowerPivot, you can sort and filter over 100 million rows of data almost in an instant – it’s very impressive indeed!</p>
<p>That’s the snazzy demo bit, but to reduce it to a glorified spreadsheet is very harsh indeed. It allows a user to import multiple data sources and combine them together into a single dimensional data model, PowerPivot will create your own personal cube, without you having to build a warehouse, without knowing anything about MDX, dimension hierarchies, attribute relationships, granularity etc. etc.</p>
<p>Microsoft’s vision and reason for creating this tool is self-service BI, allowing users to create their own cubes, data analysis environments and reporting systems. And this is where I start to have a problem…</p>
<p>I can’t remember the last time I designed a data warehouse, where I did not find significant data quality problems, conflicting data, missing data, duplicated data etc.. I also find it hard to think of a situation where an end user (even a power user) is sufficiently clued up about the intricacies of a source OLTP database to be able to extract the right data and know what to do with it. Or if they are, a dozen other people in different departments have a different idea about how things work, resulting in many different versions of the truth.</p>
<p>I’m therefore (for now!) sticking with the opinion that it is still absolutely vital for an organisation to provide a clean, consistent, dimensionally modelled data warehouse as the basis for their BI/MI infrastructure. Tools like PowerPivot then sit very nicely on top to provide an incredibly powerful and beneficial user experience, but to try and use the emergence of self-service BI tools to usher in a new ‘non-data warehouse’ era is a very dangerous route which I hope people will avoid.</p>
<p>In summary – this release brings with it a fantastic host of new tools, but with great power comes great responsibility…</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2010/05/sql-server-2008-r2-powerpivot-and-master-data-services/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Excel Cube Pivot drillthrough limited to 1000 rows</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2010/03/excel-cube-pivot-drillthrough-limited-to-1000-rows/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2010/03/excel-cube-pivot-drillthrough-limited-to-1000-rows/#comments</comments>
		<pubDate>Thu, 25 Mar 2010 09:17:45 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Cube]]></category>
		<category><![CDATA[Drillthrough]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Pivot]]></category>
		<category><![CDATA[SSAS]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=95</guid>
		<description><![CDATA[When browsing a cube using Excel 2007, you can drillthrough the measures to display up to 1000 rows of the transaction level source data.
I often get asked whether this limit of 1000 rows is configurable &#8211; well the good news is yes it is.
There is an option in the actions tab of the BIDS cube [...]]]></description>
			<content:encoded><![CDATA[<p>When browsing a cube using Excel 2007, you can drillthrough the measures to display up to 1000 rows of the transaction level source data.</p>
<p>I often get asked whether this limit of 1000 rows is configurable &#8211; well the good news is yes it is.</p>
<p>There is an option in the actions tab of the BIDS cube designer which allows you to specify the maximum rows, but helpfully this is ignored by Excel. Instead, you have to set it in Excel when you create a pivot.</p>
<p>Just click &#8220;<strong>Options</strong>&#8221; on the &#8220;<strong>PivotTable Tools</strong>&#8221; ribon, then in the &#8220;<strong>Change Data Source</strong>&#8221; dropdown click on &#8220;<strong>Connection Properties</strong>&#8220;. In this screen, just change the &#8220;<strong>Maximum number of records to retrieve</strong>&#8221; property.</p>
<p><a href="http://www.purplefrogsystems.com/blog/wp-content/uploads/2010/03/excelpivotdrillthrough.png"><img class="aligncenter size-full wp-image-96" title="excelpivotdrillthrough" src="http://www.purplefrogsystems.com/blog/wp-content/uploads/2010/03/excelpivotdrillthrough.png" alt="Excel 2007 Pivot Options" width="458" height="662" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2010/03/excel-cube-pivot-drillthrough-limited-to-1000-rows/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MDX Sub select Vs WHERE clause</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2010/03/mdx-sub-select-vs-where-clause/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2010/03/mdx-sub-select-vs-where-clause/#comments</comments>
		<pubDate>Tue, 02 Mar 2010 09:23:15 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Cube]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[WHERE]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=36</guid>
		<description><![CDATA[I&#8217;ve just read an interesting thread on the SQL Server Developer Center forum, regarding how to filter results. Specifically the difference in MDX between using a subselect
SELECT x on COLUMNS, y on ROWS
FROM ( SELECT z on COLUMNS FROM cube))
or using a where clause
SELECT x on COLUMNS, y on ROWS
FROM cube
WHERE z
In a simple query [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just read an interesting thread on the SQL Server Developer Center forum, regarding how to filter results. Specifically the difference in MDX between using a subselect</p>
<blockquote><p>SELECT x on COLUMNS, y on ROWS<br />
FROM ( SELECT z on COLUMNS FROM cube))</p></blockquote>
<p>or using a where clause</p>
<blockquote><p>SELECT x on COLUMNS, y on ROWS<br />
FROM cube<br />
WHERE z</p></blockquote>
<p>In a simple query they produce the same results, but what is the actual difference? You can read the full thread <a href="http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/3f0a2aba-93de-4f67-8402-181798a6225f" target="_blank">here</a>, but to summarise Darren Gosbell&#8217;s response&#8230;</p>
<p>Using the WHERE clause sets the query context and consequently the CurrentMember. This then enables functions such as YTD and PerdiodsToDate to work.</p>
<p>Using a subselect can provide improved performance, but does not set the context.</p>
<p>Simples..!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2010/03/mdx-sub-select-vs-where-clause/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scope Problems with MDX Calculated Members</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2009/11/scope-problems-with-mdx-calculated-members/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2009/11/scope-problems-with-mdx-calculated-members/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 13:02:34 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Calculated Member]]></category>
		<category><![CDATA[Cube]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[Scope]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=21</guid>
		<description><![CDATA[We were recently investigating a problem for a client regarding the use of Scope within MDX calculated members. The code in question was similar to this:
CREATE MEMBER
   CURRENTCUBE.[Measures].[Test Measure To Date]
   AS "NA", VISIBLE = 1;
Scope([Date].[Calendar].MEMBERS);
    [Measures].[Test Measure To Date] =
      SUM(NULL:[Date].[Calendar].CurrentMember,
  [...]]]></description>
			<content:encoded><![CDATA[<p>We were recently investigating a problem for a client regarding the use of Scope within MDX calculated members. The code in question was similar to this:</p>
<pre><span style="color: #008000;">CREATE MEMBER
   CURRENTCUBE.[Measures].[Test Measure To Date]
   AS "NA", VISIBLE = 1;
Scope([Date].[Calendar].MEMBERS);
    [Measures].[Test Measure To Date] =
      SUM(NULL:[Date].[Calendar].CurrentMember,
        [Measures].[Test Measure]);
End Scope;
Scope([Date].[Fiscal].MEMBERS);
    [Measures].[Test Measure To Date] =
      SUM(NULL:[Date].[Fiscal].CurrentMember,
        [Measures].[Test Measure]);
End Scope;</pre>
<p></span></p>
<p>Essentially the warehouse was providing a transaction table with credits and debits, this calculated measure was supposed to provide the current balance, summing all transactions to date (not just the current year/period etc, but the entire history). Scope is used to enable the calculation to work across two different date hierarchies, calendar and fiscal.</p>
<p>The problem was that even when the [Date].[Calendar] hierarchy was selected, the code still used the fiscal hierarchy to calculate the value.</p>
<p>This is caused by the fact that [Date].[Fiscal].MEMBERS includes the member [Date].[Fiscal].[All]. Consequently, even when the Fiscal hierarchy was not included in the query, its [All] member was effectively still within the scope. Thus the fiscal calculation was overriding the calendar calculation no matter what was selected.</p>
<p>The solution to this is to exclude [All] from the scope, which can be done by changing the code to the following:</p>
<pre><span style="color: #008000;">CREATE MEMBER
   CURRENTCUBE.[Measures].[Test Measure To Date]
   AS "NA", VISIBLE = 1;
Scope(DESCENDANTS([Date].[Calendar],,AFTER));
    [Measures].[Test Measure To Date] =
      SUM(NULL:[Date].[Calendar].CurrentMember,
        [Measures].[Test Measure]);
End Scope;
Scope(DESCENDANTS([Date].[Fiscal],,AFTER));
    [Measures].[Test Measure To Date] =
      SUM(NULL:[Date].[Fiscal].CurrentMember,
        [Measures].[Test Measure]);
End Scope;</pre>
<p></span></p>
<p>DESCENDANTS(xxx,,AFTER) is a simple way of identifying every descendent of the hierarchy AFTER the current member, which is [All] when not specified.</p>
<p>Problem solved, Frog-blog out.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2009/11/scope-problems-with-mdx-calculated-members/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Excel 2007 and SSAS 2008 Error</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2009/10/excel-2007-and-ssas-2008-error/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2009/10/excel-2007-and-ssas-2008-error/#comments</comments>
		<pubDate>Fri, 30 Oct 2009 16:56:06 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[OLAP]]></category>
		<category><![CDATA[Pivot]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=20</guid>
		<description><![CDATA[I was working on a new SSAS 2008 cube today, and came across an error which Google was unable to help with. I thought I&#8217;d post the solution here to help anyone else who may encounter it.
The cube in question will be primarily be accessed using Excel 2007, so I&#8217;d been dutifully testing it along [...]]]></description>
			<content:encoded><![CDATA[<p>I was working on a new SSAS 2008 cube today, and came across an error which Google was unable to help with. I thought I&#8217;d post the solution here to help anyone else who may encounter it.</p>
<p>The cube in question will be primarily be accessed using Excel 2007, so I&#8217;d been dutifully testing it along the way to ensure all was well. And then, after a number of changes the following error appeared when connecting to the cube from Excel to create a pivot table.</p>
<p><span style="color: #008000;">Excel was unable to get necessary information about this cube. The cube might have been reorganized or changed on the server.</p>
<p>Contact the OLAP cube administrator and, if necessary, set up a new data source to connect to the cube<br />
</span></p>
<p>Connecting and querying the cube via SSMS or BIDS worked without error (hense I didn&#8217;t spot the error sooner!).</p>
<p>A quick Google revealed a number of posts regarding this error, but they all related to attributes containing <a href="http://support.microsoft.com/kb/210806" target="_blank">invalid characters</a> when accessed from Excel 2000 Or problems with <a href="http://social.msdn.microsoft.com/Forums/en-US/sqlanalysisservices/thread/22796693-6060-483c-9071-84965d3536a7" target="_blank">translations and locale settings</a> in the .oqy file. Neither of these was the cause here, so I had to go back and recreate every change I had made step by step to track the problem.</p>
<p>Well, I&#8217;m please to report that in the end it was nothing more that a simple spelling mistake in a named set. One of the dynamic named sets in the cube calculations referred to a specific member of a dimension, which was spelled slightly incorrectly. (Simplified example..)</p>
<pre><span style="color: #008000;">CREATE DYNAMIC SET CURRENTCUBE.[Set1]
 AS {[Dimension].[Attribute].[Value1],
     [Dimension].[Attribute].[Value2WithTypo]
    };
</span></pre>
<p>When querying calculated measures through MDX in SSMS, the MDX parser just ignored the problem and only uses the valid members, however it appears as though Excel 2007 is slightly more picky with its cubes.</p>
<p>Useful to know, and even more useful when used as a tool to double check for any errors in the MDX calculations.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2009/10/excel-2007-and-ssas-2008-error/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Dynamic MDX in Reporting Services</title>
		<link>http://www.purplefrogsystems.com/blog/index.php/2008/09/dynamic-mdx-in-reporting-services/</link>
		<comments>http://www.purplefrogsystems.com/blog/index.php/2008/09/dynamic-mdx-in-reporting-services/#comments</comments>
		<pubDate>Thu, 18 Sep 2008 14:28:36 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Analysis Services]]></category>
		<category><![CDATA[Reporting Services]]></category>
		<category><![CDATA[SQL Server]]></category>
		<category><![CDATA[Dynamic]]></category>
		<category><![CDATA[MDX]]></category>
		<category><![CDATA[OLAP]]></category>

		<guid isPermaLink="false">http://www.purplefrogsystems.com/blog/?p=18</guid>
		<description><![CDATA[After a couple of days off work last week with SQL Bits III and SQL 2008 Unleashed, it&#8217;s back to the grindstone this week; however before I get onto the serious stuff I&#8217;d like to say thank you to the organisers of both events. Watching you on stage headbanging to Rockstar &#8211; legendary! (You can [...]]]></description>
			<content:encoded><![CDATA[<p>After a couple of days off work last week with SQL Bits III and SQL 2008 Unleashed, it&#8217;s back to the grindstone this week; however before I get onto the serious stuff I&#8217;d like to say thank you to the organisers of both events. Watching you on stage headbanging to Rockstar &#8211; legendary! (You can see for yourself <a href="/images/blog/rockstar1.jpg" target="_blank">here</a> and <a href="/images/blog/rockstar2.jpg" target="_blank">here</a>&#8230;).</p>
<p>Anyway, back to MDX&#8230;</p>
<p>This post explains how you can build a dynamic MDX query in Reportins Services, customised to the users requirements. This can often bring some quite major performance benefits.</p>
<p>Lets say for example that you want to have a sales report grouped dynamically by either product, sales person, department or customer. Normally you would use a single static MDX query, and then add a dynamic grouping to the table in the report. This is fine, until you try it on a large dataset. If you only have 50 products, 2 salesmen, 5 departments and 100 customers, your MDX needs to return 50,000 records, the report then has to summarise all of this into the level of grouping you want. This renders the pre-calculated aggregations in OLAP pretty much worthless.</p>
<p>To get around this, you can generate your MDX dynamically, so that the query returns the data already grouped into the correct level. You can also use this to add extra filters to the query, but only when they are required.</p>
<p>To start with, lets see how we would do this normally with SQL. Assuming we&#8217;re working from a denormalised table such as this</p>
<table width="100%" align="center">
<tbody>
<tr>
<td align="center"><img src="/images/blog/DynamicMDXtable.png" alt="Dynamic MDX Table" /></td>
</tr>
</tbody>
</table>
<p>Dynamic SQL is pretty simple, instead of having your dataset query as</p>
<pre><span style="color: #008000;">  SELECT SalesPerson,
      Sum(Sales) AS Sales
   FROM tblData
   GROUP BY SalesPerson
</span></pre>
<p>you can add a report parameter called GroupBy,</p>
<table width="100%" align="center">
<tbody>
<tr>
<td align="center"><img src="/images/blog/DynamicMDXSQL.png" alt="Dynamic MDX SQL" /></td>
</tr>
</tbody>
</table>
<p>and then use an expression as your dataset</p>
<pre><span style="color: #008000;">  ="SELECT "
      + Parameters!GroupBy.Value + " AS GroupName,
      Sum(Sales) AS Sales
   FROM tblData
   GROUP BY " + Parameters!GroupBy.Value
</span></pre>
<p>However MDX queries don&#8217;t let you use an expression in the dataset, so we have to work around that quite major limitation. To do this we make use of the OpenRowset command. You need to enable it in the surface area config tool, but once it&#8217;s enabled you can fire off an OpenRowset command to SQL Server, which will then pass it on to the cube. As the datasource connnection is to SQL Server not Analysis Services, it allows you to use an expression in the dataset.</p>
<pre><span style="color: #008000;">  ="SELECT * FROM OpenRowset('MSOLAP',
    'DATA SOURCE=localhost; Initial Catalog=SalesTest;',
    'SELECT
      {[Measures].[Sales]} ON 0,
      NON EMPTY {[Product].[Product].[Product].Members} ON 1
      FROM Sales') "
</span></pre>
<p>You can then expand this to make it dynamic depending on the value of a parameter. Before we do this though, there are a couple of items I should point out.<br />
1) As the expression can get quite large, I find it much easier to create the query from a custom code function<br />
2) As SSRS can&#8217;t interpret the expression at runtime, you need to define the fields in your dataset manually (more on this later)</p>
<p>To use a custom code function, just change the dataset expression to</p>
<pre><span style="color: #008000;">  =Code.CreateMDX(Parameters)</span></pre>
<p>We pass in the parameters collection so that we can use the parameters to determine the query. Create a function called CreateMDX() in the code block</p>
<table width="100%" align="center">
<tbody>
<tr>
<td align="center"><img src="/images/blog/DynamicMDXCode.png" alt="Dynamic MDX Code" /></td>
</tr>
</tbody>
</table>
<p>You can then construct your MDX query within the code block.</p>
<pre><span style="color: #008000;">  Public Function CreateMDX(ByVal params as Parameters) as string

   Dim mdx as string 

   mdx = "SELECT * FROM OpenRowset("
   mdx += " 'MSOLAP', "
   mdx += " 'DATA SOURCE=localhost; Initial Catalog=SalesTest;', "
   mdx += " ' SELECT {[Measures].[Sales]} ON 0, "
   mdx += "    NON EMPTY {[Product].[Product].[Product].Members} ON 1 "
   mdx += "   FROM Sales ' "
   mdx += ")"

   return mdx

End Function
</span></pre>
<p>We&#8217;re almost there&#8230;<br />
The next problem is that the field names returned by the query are less than helpful. To fix this we just need to alias the fields in the query. I usually take the opportunity of casting the numerical fields so that the report treats them as such, rather than as a string.</p>
<pre><span style="color: #008000;">  Public Function CreateMDX(ByVal params as Parameters)
                  as string

   Dim mdx as string 

   mdx = "SELECT "
   mdx += "  ""[Product].[Product].[Product].[MEMBER_CAPTION]"" AS GroupName, "
   mdx += "   Cast(""[Measures].[Sales]"" AS int) AS Sales "
   mdx += " FROM OpenRowset("
   mdx += " 'MSOLAP', "
   mdx += " 'DATA SOURCE=localhost; Initial Catalog=SalesTest;', "
   mdx += " ' SELECT {[Measures].[Sales]} ON 0, "
   mdx += "    NON EMPTY {[Product].[Product].[Product].Members} ON 1 "
   mdx += "   FROM Sales ' "
   mdx += ")"

   return mdx

End Function
</span></pre>
<p>(please do watch out for the quotes, double quotes and double double quotes, it can get a little confusing!)<br />
We then need to tell the dataset which fields to expect from the query.</p>
<table width="100%" align="center">
<tbody>
<tr>
<td align="center"><img src="/images/blog/DynamicMDXFields.png" alt="Dynamic MDX Fields" /></td>
</tr>
</tbody>
</table>
<p>You can now use the dataset in your report.<br />
However, the original point of this was to make the query dynamic&#8230; All we need to do to achieve this is expand the VB.Net code accordingly.</p>
<pre><span style="color: #008000;">  Public Function CreateMDX(ByVal params as Parameters) as string

   Dim mdx as string 

   mdx = "SELECT "

IF params("GroupBy").Value.ToString()="Product" THEN
   mdx += "  ""[Product].[Product].[Product]"
ELSE IF params("GroupBy").Value.ToString()="SalesPerson" THEN
   mdx += "  ""[Sales Person].[Sales Person].[Sales Person]"
ELSE IF params("GroupBy").Value.ToString()="Customer" THEN
   mdx += "  ""[Customer].[Customer].[Customer]"
END IF

   mdx += ".[MEMBER_CAPTION]"" AS GroupName, " 

   mdx += "   Cast(""[Measures].[Sales]"" AS int) AS Sales "
   mdx += " FROM OpenRowset("
   mdx += " 'MSOLAP', "
   mdx += " 'DATA SOURCE=localhost; Initial Catalog=SalesTest;', "
   mdx += " ' SELECT {[Measures].[Sales]} ON 0, "

IF params("GroupBy").Value.ToString()="Product" THEN
   mdx += "  NON EMPTY {[Product].[Product].[Product]"
ELSE IF params("GroupBy").Value.ToString()="SalesPerson" THEN
   mdx += "  NON EMPTY {[Sales Person].[Sales Person].[Sales Person]"
ELSE IF params("GroupBy").Value.ToString()="Customer" THEN
   mdx += "  NON EMPTY {[Customer].[Customer].[Customer]"
END IF

   mdx += ".Members} ON 1 "

   mdx += "   FROM Sales ' "
   mdx += ")"

   return mdx

End Function
</span></pre>
<p>It&#8217;s certainly not that simple, and debugging can cause a few headaches, but you can benefit from a massive performance in complex reports if you&#8217;re prepared to put the work in.</p>
<table width="100%" align="center">
<tbody>
<tr>
<td align="center"><img src="/images/blog/DynamicMDXResults.png" alt="Dynamic MDX Results" /></td>
</tr>
</tbody>
</table>
<p>You can download the project files <a href="/Download/blog/DynamicMDX.zip"><strong>here</strong></a></p>
<p>As always, please let me know how you get on with it, and shout if you have any queries&#8230;</p>
<p>Alex</p>
]]></content:encoded>
			<wfw:commentRss>http://www.purplefrogsystems.com/blog/index.php/2008/09/dynamic-mdx-in-reporting-services/feed/</wfw:commentRss>
		<slash:comments>32</slash:comments>
		</item>
	</channel>
</rss>
