Thursday, July 26, 2007 - Posts

Drillthrough failed because the coordinate identified by the SELECT clause is out of range: Cause and Solution

Drillthrough failed because the coordinate identified by the SELECT clause is out of range.

Ever gotten message shown above when using DRILLTHROUGH in SSAS? I prepared the Integrating Analysis Services 2005 and Reporting Services 2005 with DRILLTHROUGH series after encountering significant problems with drillthrough on a real project that absolutely required drillthrough. Solving the drillthrough mystery was not the easiest problem ever solved, and just when we thought every problem was conquered, another one struck.

My teammate encountered this error while authoring a report that quried a sample SSAS database I built with data only for October 2006.  (The database was for a client.) Despite only one month if fact data, the Date dimension had several years’ members. He wrote a multidimensional selector component which extended Reporting Services to navigate a multidimensional hierarchy, and he was testing this with the report using our newfound drillthrough solution.

His initial query looked like this:

DRILLTHROUGH

SELECT

NON EMPTY [Measures].[SomeMember] ON COLUMNS

FROM

[SomeCube]

WHERE

[Date].[Calendar].[Month].[Oct 2006]

He then parameterized the query to insert any month into the WHERE clause after the user picked a month in the selector component. While testing, everything worked as long as he picked October 2006, which actually had data. As soon as he picked any month other than October 2006, a strange error occurred, shown below:

How can a coordinate identified by the SELECT clause of an MDX query be out of range? By definition, SSAS requires one coordinate from every hierarchy, andd if one is not supplied by the query then SSAS uses default members. It seems impossible to "identify" a coordinate that is "out of range."

I conjured two possible causes.

  1. In SSRS, a DMX query is used to make drillthrough work. Perhaps this was an error related to DMX.
  2. The error had nothing to do with MDX or DMX at all. Since drillthrough queries are not answered as MDX queries, perhaps this error was actually thrown by the code executing the DRILLTHROUGH statement.

I had no way of directly testing the first possibility. But I was able to triangulate to the second possibility because the MDX query worked perfectly when the DRILLTHROUGH keyword was removed. I also knew that the query could only return one cell because by definition, drillthrough acts upon a single cell.  For Oct 2006, the returned cell had a numerical value because the dates descended from Oct 2006 had data. For Sep 2006, the returned cell had a NULL numerical value because none of the dates descended from Sep 2006 had data. Said in the vernacular, the cell was empty.

To illustrate this, I’ve modified Adventure Works DW by deleting the Reseller_Sales_2003 partition in the Reseller Sales measure group. The following query shows that there is now no data for [Ship Date].[Calendar].[Calendar Year].&[2003].

SELECT

Measures.[Reseller Sales Amount] ON COLUMNS,

[Ship Date].[Calendar].[Calendar Year].Members ON ROWS

FROM

[Adventure Works]

That query returns the following cellset.m  Note that CY 2003 is now empty, a result of deleting the the partition with CY 2003's data.

The following query is analogous to the real-world query which produced the error, but without the DRILLTHROUGH keyword.

SELECT

NON EMPTY Measures.[Reseller Sales Amount] ON COLUMNS

FROM

[Adventure Works]

WHERE

[Ship Date].[Calendar].[Calendar Year].&[2003]

That query returned the following cellset.

Two interesting observations emerge from the answer returned to Microsoft SQL Server Management Studio.

  1. The Results tab is completely blank.  (Not shown in the screenshot above.)
  2. The Messages tab, however, displays the information pictured below.

This message indicates that the cell set consists of 1 row and 0 columns. To be honest, I’m not sure what this means, but I know it is significant because things change when the NON EMPTY keyword is removed.

First, the Results tab is no longer blank, as shown below.

Second, the Messages tab has a different message than before.

So, comparing the two, when the NON EMPTY keyword is present, no cells are returned, and "1 rows and 0 columns" is the technical way of describing this. When the NON EMPTY keyword is removed, one empty cell is returned (as expected) and "2 rows and 1 columns" is the technical way to say this.

At this point I had a major clue. This must be a problem when DRILLTHROUGH was combined with NON EMPTY. Removing NON EMPTY and putting DRILLTHROUGH back in the query returned the following result.

And this was the Messages tab.

Bingo! The error at the beginning of this article is caused when drillthrough executes on a cellset that does not exist. The following two items are now evident.

  1. DRILLTHROUGH will not work when the cell set consists of zero cells, which would be produced by a NON EMPTY query against a cell which has no data.  This is perfectly sensible since drillthrough acts upon a single cell.  Naturally, when there is no cell, there can be no drillthrough.
  2. DRILLTHROUGH will work when the cell set consists of one empty cell. In such a case, DRILLTHROUGH returns no rowset, which is the expected case for an empty cell since it has no value. There is no fact row for this cell; DRILLTHROUGH should return nothing.

In other words, DRILLTHROUGH must have a real cell set upon which to act, even if that cell set is a lone empty cell. This gives rise to an important rule for drillthrough queries.

Do not use the NON EMPTY keyword in a DRILTHROUGH query.

IMPORTANT NOTE: This rule applies ONLY to queries using the DRILLTHROUGH keyword. As noted in my four parter on drillthrough, it is possible to emulate a drillthrough query by using a crossjoin MDX query. The NON EMPTY prohibition does NOT apply to the crossjoin approach; indeed, NON EMPTY may be desired in certain circumstances.

Integrating Analysis Services 2005 and Reporting Services 2005 with DRILLTHROUGH: Part IV of IV

CONCLUSION

Drillthrough is changed substantially in SSAS because Microsoft rearchitected it. SSAS will no longer prepare an SQL statement to pass through the data provider to the data source, and pass along a rowset returned by the data source. All drillthrough queries must be answered from SSAS, using the information present in UDM.

The goal of drillthrough in SSAS should be the same as it was for MSAS: return one row for each row in the fact table, regardless of how many detail cells are underneath the cell upon which drillthrough occurs. (NOTE:  I am aware that drillthrough is actually more sophisticated than this and can return rowsets at nearly any grain, but if it will not produce the fact row set, then flexibility is limited.)  Since SSAS now answers all drillthrough queries directly, savvy DW/BI designers must adhere to several prominent design elements, most notably enforcement of fact row uniqueness. The goal is to produce a one-to-one relationship between fact rows and detail cube cells. One cell should have one and only one fact row.

While SSAS will work fine without unique fact rows for aggregate and analytical queries, it simply cannot produce the most granular drillthrough query without fact row uniqueness. Decide whether drillthrough requirements require fact row uniqueness before ETL and cube builds, because it may be very difficult to add once a cube is in production.

Add a dimension with an attribute to hold the column or columns that make fact rows unique. This attribute will have as many members as rows in the fact table, so it could be very large. Take steps to control it. Techniques include making it a ROLAP dimension and perhaps hiding it if it is useful only to drillthrough queries. This dimension ties into a measure group by using the fact dimension relationship.  CAUTION:  ROLAP dimensions must be processed the first time they are queried, which could result in extraordinarily long query times.  Cnosider MOLAP first.

Once the one-to-one relationship between fact rows and detail cells is enforced, drillthrough queries can be written with two divergent techniques. The first is to use the DRILLTHROUGH keyword in an MDX query. The DRILLTHROUGH keyword requires an MDX query that returns a single cell, and then returns one row for each detail cell under the single cell. The second is to use an MDX statement to emulate drillthrough and produce a cell set. This is done with an inordinate number of crossjoins, but it works.

Even though these two query options produce the same answer, choose one or the other carefully based on performance. The query using the DRILLTHROUGH keyword does not execute as an MDX query and basic testing shows it is faster than its crossjoin counterpart. Indeed, be very wary of the crossjoin alternative. Crossjoin queries slow down considerably as the number of members being crossed increased, and since the fact dimension contains one member for each fact row, the crossjoin approach can become unwieldly very quickly.  Remember, the point of this series is to integrate SSRS with SSAS using drillthrough, and drillthrough returns a nice, flattened rowset convenient for SSRS.

Integrating Reporting Services 2005 and Analysis Services 2005 with DRILLTHROUGH: Part III of IV

I have been most delinquent in finishing this multi-part series on drillthrough with SSAS and SSRS.  I wrote all the parts of this series at one time in December, 2006, but only posted two.  Four weeks ago a client asked about specific problems with drillthrough, and I had all the answers he needed in the total blog series, including pieces that I hadn't published.  I though that perhaps I should finish posting the series.

Parts I and II of this series demonstrated the differences in drillthrough from MSAS to SSAS, and listed design implications for the entire DW/BI manufacturing pipeline. This section discusses ways to write effective drillthrough queries.

The introduction of this series stated that web research did not provide a single, conclusive way to handle drillthrough in SSAS. As noted, the first hint of trouble was the inability of SSRS to use DRILLTHROUGH in an MDX query. SSRS returned the following error: "Failed to parse the query to detect if it is MDX or DMX. (MDXQueryGenerator)".

http://connect.microsoft.com/SQLServer/feecback/ViewFeedback.aspx?FeedbackID=126175 shows the bug and Microsoft’s response, which is that drillthrough queries are not supported in the SSAS integration with SSRS because MDX can effectively duplicate the fact rowset. Part I of this series demonstrated empirically that this statement is not always true. Part II outlined the conditions in which the statement is true, and how those conditions influence design.

A Web search reveals two workarounds.

  1. Use the OLE DB for OLAP 9.0 provider. http://groups.google.com/group/microsoft.public.sqlserver.olap/msg/85a65872f286686b
  2. Darren Gosbel posted a second workaround, using a DMX query with the DRILLTHROUGH keyword. This works surprisingly well. http://connect.microsoft.com/SQLServer/feedback/Workaround.aspx?FeedbackID=126175  

So, apparently there are three ways to write drillthrough when integrating SSRS with SSAS.

  • Use the OLE DB for OLAP 9.0 provider instead of a native provider. This approach is undesirable if the source is SQL Server, since the native provider probably performs better OLE DB. It may also affect parameterization in SSRS, and it makes little sense to use a query that limits reporting functionality. This is "the old way" complete with the drawbacks of "the old way."
  • Use a DMX query with the DRILLTHROUGH keyword. As noted, this works quite well but it requires any new report writer to know the workaround.
  • Write a crossjoin MDX query that returns the correct rowset.

Option (1) is discarded. That leaves options (2) and (3). The following examples illustrate how they work.

Example for Option (2): DRILLTHOUGH with an MDX query.

The following example illustrates how the DRILLTHROUGH keyword works with an MDX query (and also with a DMX query in SSRS). Like Parts I and II, this example uses the Adventure Works DW cube and the Reseller Sales measure group. (All of these queries may be run in SQL Server Management Studio.)

The following is the most basic drillthrough MDX query:

DRILLTHROUGH MAXROWS 100000

SELECT

[Measures].[Reseller Sales Amount] ON COLUMNS

FROM

[Adventure Works]

It returns the following columns:

[Reseller Sales].[Reseller Sales Amount]

[Reseller Sales].[Reseller Order Quantity]

[Reseller Sales].[Reseller Extended Amount]

[Reseller Sales].[Reseller Tax Amount][Reseller Sales].[Reseller Freight Cost]

[Reseller Sales].[Discount Amount]

[Reseller Sales].[Reseller Unit Price]

[Reseller Sales].[Unit Price Discount Percent]

[Reseller Sales].[Reseller Total Product Cost]

[Reseller Sales].[Reseller Standard Product]

[$Reseller].[Reseller]

[$Promotion].[Promotion]

[$Employee].[Employee]

[$Delivery Date].[Date]

[$Sales Territory].[Sales Territory Region]

[$Reseller Sales Order Details].[Carrier Tracking Number]

[$Reseller Sales Order Details].[Customer PO Number]

[$Reseller Sales Order Details].[Sales Order Number]

[$Reseller Sales Order Details].[Sales Order Line]

[$Product].[Product]

[$Ship Date].[Date]

[$Source Currency].[Source Currency Code]

[$Date].[Date]

[$Geography].[City]

[$Geography].[State-Province]

[$Geography].[Country]

[$Destination Currency].[Destination Currency Code]

Several observations emerge from the results set:

  1. The query returns 80,655 rows. This is the exact number of rows in the fact table underneath the Reseller Sales measure group, and is the correct answer. Since SSAS answers all drillthrough queries and does not pass the request on to the data source, the one-to-one relationship between detail cell and fact row is evidenced.
  2. Dimension columns are prefixed with a "$". Measure columns have no such prefix.
  3. Ten measures are returned by the query. These are the ten measures with their Visible property set to True. Those measures with their Visible property set to False are not returned by default. They can be returned if the optional RETURN keyword is used and the columns are explicitly listed therein.
  4. Both the Reseller Sales Order Details and Geography dimension returned non-key attributes. This is because their key attributes have their AttributeHierarchyVisible property set to False.
  5. All other dimensions have key attributes with AttributeHierarchyVisible property set to True. These dimensions return only their key attribute.

Additional attributes and hidden measures may be returned with this query if the RETURN keyword is used. However, this will require all return columns to be explicitly listed in the RETURN clause. RETURN also permits column aliasing, which may particularly useful to comply with organizational standards for SSRS data set column names.

Additional considerations apply.

  1. Of course, a WHERE clause may be added to this query as required.
  2. It does not matter which measure is called in AXIS (0); the query always returns the same set of columns (absent the RETURN clause).
  3. The query sends CPU utilization for msmdsrv.exe to maximum capacity. This test was conducted on a laptop with a P4 HT, and only one of the virtual CPU’s answered the query.
  4. There appears to be some caching effect. The first query took about four minutes to run. Repeating the query reduced completion time to 10’s of seconds.
  5. DRILLTHROUGH will not return calculated members. Anything returned by DRILLTHROUGH must be tied directly to an attribute or measure, which in turn relies directly upon a DSV column.

Example for Option (3): Emulating DRILLTHROUGH with an MDX Query.

The following example illustrates how MDX may be used to emulate a DRILLTHROUGH query. This example assumes that the proper design criteria have been met to emulate drillthrough with MDX. (See part II of this series.) This example uses the Adventure Works DW cube and the Reseller Sales measure group. (All of these queries may be run in SQL Server Management Studio.)

Deepak Puri correctly assessed the lone requirement to emulate a drillthrough query with MDX when he said, "…you need to include the fact dimension key attribute, so that each fact table row is returned, regardless of how many contribute to each cell." Any other attribute or measure in the query may add content, but it will not change the number of rows returned by the query.

The following query returns 60,855 rows from Reseller Sales in Adventure Works DW.

SELECT

[Measures].Members ON COLUMNS,

NON EMPTY

[Reseller Sales Order Details].[Reseller Sales Orders].[Order Line] ON ROWS

FROM

[Adventure Works]

Observations about this query include the following:

  1. The query returns 60,855 rows. This is the exact number of fact rows and provides evidence that MDX queries can be used to emulate drillthrough so long as the proper design techniques are employed.
  2. This query returned all physical measures in the cube. Since not all measures originate with the Reseller Sales measure group, not all measures can be sliced by the Reseller Sales Order Details dimension. The values returned by those measures will be for the All member in that dimension and will have the same large value in every row. Be sure to explicitly list the measures to be returned in the query.
  3. This query returned no calculated members.
  4. A WHERE clause may be added as required.
  5. Caching effect is large. The first time the query was run execution time was 10:12. The second time the query was run execution time was 3:06.
  6. Performance conditions were identical to the previous example since the same machine was used, in the same configuration.

Additional attributes may be added as desired to the previous query.

Is it possible to prove that the only important part of drillthrough emulation is to include the key attribute of the fact dimension? Indeed it is. Suppose the previous query is altered so that [Reseller Sales Order Details].[Reseller Sales Orders].[Order Line] is replaced by [Date].[Date].[Date] to form the query shown below.

SELECT

[Measures].Members ON COLUMNS,

NON EMPTY [Date].[Date].[Date] ON ROWS

FROM

[Adventure Works]

This query returns 1,159 rows and clearly does NOT emulate drillthrough.

What is required to make this query return multiple attributes while still emulating drillthrough? Crossjoins. Lots and lots of crossjoins. The previous query is modified to reinsert [Reseller Sales Order Details].[Reseller Sales Orders].[Order Line] to make it a drillthrough query again, as shown below.

SELECT

[Measures].Members ON COLUMNS,

NON EMPTY { [Date].[Date].[Date] *

[Reseller Sales Order Details].[Reseller Sales Orders].[Order Line] } ON ROWS

FROM

[Adventure Works]

This particular query takes a very long time to run but it returns 60,855 rows, as expected. Specifying a single measure instead of [Measures].Members on Axis 0 would make the query much faster.

So, Microsoft really DID know what they were talking about.  You can either use the DRILLTHROUGH keyword, or model UDM so that MDX produces a granular rowset.