About the Series ...
This article is a member of the series, MDX Essentials.
The series is designed to provide hands-on application of the fundamentals of
the Multidimensional Expressions (MDX) language, with each tutorial
progressively adding features designed to meet specific real-world needs.
For more information about the series in general, as well as
the software and systems requirements for getting the most out of the lessons
included, please see my first article, MDX at First Glance: Introduction to MDX Essentials.
Note: Current updates are assumed for MSSQL
Server, MSSQL Server Analysis Services, and the related Books
Online and Samples.
Overview
In
this lesson, we will introduce StripCalculatedMembers(), a basic set function
which is often just what the doctor ordered in the context of the specific
need. The general purpose of StripCalculatedMembers() is to retrieve the
members of a specified set, after removing any calculated
members.
StripCalculatedMembers()
can be leveraged
in a wide range of activities, from the support of simple list generation, to the
support of sophisticated conditional and other calculations and presentations.
We will introduce the function, commenting upon its operation and touching upon
creative effects that we can employ it to deliver. As a part of our
discussion, we will:
-
Examine the syntax surrounding the function;
-
Undertake illustrative examples of the uses of the function in
practice exercises;
-
Briefly discuss the results datasets we obtain in the practice
examples.
The StripCalculatedMembers() Function
Introduction
According to the Analysis Services Books Online, the StripCalculatedMembers()
function returns a set generated by removing calculated members from a
specified set. StripCalculatedMembers() has numerous applications. For
example, the function can be leveraged within queries to create datasets, in
reporting applications such as MSSQL Server Reporting Services, for the
support of picklists within the reports, for the support of axes within various
end presentations, and so forth. The StripCalculatedMembers() function
provides an intuitive option anytime we need to present, in a returned dataset,
all members minus calculated members that belong to a specified
set.
As we have noted to have been the case
with many individual MDX functions we have examined within this series,
combining StripCalculatedMembers()
with other functions allows us to further extend its power. We will get a taste
of this synergy in the practice exercises that follow.
We will examine the syntax for the StripCalculatedMembers()
function after a brief discussion in the next section. We will then explore,
from the straightforward context of MDX queries, and within practice examples
constructed to support hypothetical business needs, some of the capabilities it
offers the knowledgeable user. This will allow us to activate what we explore
in the Discussion and Syntax sections, and afford
us some hands-on exposure in creating expressions that employ the StripCalculatedMembers()
function.
Discussion
To restate our initial explanation of its
operation, the StripCalculatedMembers() function examines a set expression that we specify
and returns the members that remain after it removes all calculated
members. StripCalculatedMembers()
can be used for a great deal more
than simple list retrieval, as we have intimated. When coupled with other
functions or used within MDX scripts, among other applications, we can leverage
StripCalculatedMembers() to support a wide range of analysis and
reporting utility.
Lets discuss syntax to further clarify the operation of StripCalculatedMembers().
Syntax
Syntactically, in using the StripCalculatedMembers()
function to return a set of members (minus calculated members), the
set expression upon which we seek to apply the function is specified within
the parentheses to the right of the StripCalculatedMembers keyword. The
function removes calculated members from the set expression (a
valid MDX expression that returns a set) enclosed within the parentheses,
and returns a set representing only the base members contained
within the scope of the set expression. As we shall see, StripCalculatedMembers()
removes all calculated members from a set, including those
added within the query itself (via the WITH MEMBER keywords). StripCalculatedMembers()
also removes all calculated members added to a specified set
using either of the AddCalculatedMembers() or .AllMembers functions,
both of which return calculated members defined on the Analysis
Server.
The general syntax for the
application of StripCalculatedMembers() appears in the following string:
StripCalculatedMembers( <<Set_Expression>> )
Putting StripCalculatedMembers() to work is
straightforward. When using the function to return the members, minus
any calculated members, contained within a set expression, we
simply supply the required set expression within the parentheses
to the right of the StripCalculatedMembers keyword.
As an example, say we specify, within a query executed
against the sample Adventure Works cube, a column axis containing all
members of the Product Categories level of the Product dimension
(specified as {[Product].[Product Categories].[Category].MEMBERS}), with
a row axis such as the following:
STRIPCALCULATEDMEMBERS( {[Measures].ALLMEMBERS} )
Moreover,
say that we add a WHERE clause to filter the retrieved data set to Calendar
Year 2004. Depending upon the calculated members we have defined
within our cube (we might have added calculated members beyond those that
appear in the pristine sample cube), we would expect to retrieve results
similar to those depicted in Illustration 1.
Illustration 1: Example Returned Data: StripCalculatedMembers()
Function Employed in Query
We can see, within the dataset
returned above, that only base members / measures appear. (If we remove
the StripCalculatedMembers() from around the rest of the row axis
specification, we will see that a greater number of measures (both base
and calculated) now appear, and that the column axis increases
dramatically (from 30 measures, in my local cube, to 50-plus measures).
Because of the relative ease
with which we can employ StripCalculatedMembers(), and because of the
flexibility with which we can exploit it to meet various business needs
(particularly those meeting metadata requirements), the function can become a
popular member of our analysis and reporting toolsets. It is easy, for
example, when considering the above scenario, to see that we might simply
parameterize on / off behavior for the StripCalculatedMembers() function
within a client application, such as Reporting Services, to allow
information consumers to choose either include or exclude behavior with
regard to calculated members within axes or picklists at report run
time.
We will get some hands-on
exposure to the StripCalculatedMembers() function in the section that
follows.
Practice
Preparation: Access SQL Server Management Studio
To reinforce our understanding of the basics we have
covered, we will use the StripCalculatedMembers() function within queries
that illustrate its operation. The intention, of course, is to demonstrate the
use of StripCalculatedMembers() in a straightforward, memorable manner.
We will turn to the SQL Server Management Studio as a
platform from which to construct and execute the MDX we examine, and to view
the results datasets we obtain. If you do not know how to access the SQL
Server Management Studio in preparation for using it to query an Analysis
Services cube (we will be using the sample Adventure Works cube in
the Adventure Works DW Analysis Services database), please
perform the steps of the following procedure, located in the References
section of my articles index:
This procedure will take us through opening a new Query
pane, upon which we can create our first query within the section that follows.
Procedure: Satisfy Business Requirements with MDX
As a basis for our practice example, we will assume that we
have received a request for assistance from representatives of our client, the Adventure
Works organization. As we have noted in other articles of the series, the
Reporting department, a group of client-facing authors and developers, often
requests assistance with designing queries to support organizational analysis
and reporting efforts. As a part of our relationship with Adventure Works,
as well as with other clients, we provide on-site staff augmentation for
business requirements gathering and training, as well as for combined
development workshops and train the trainer events.
In a brief discussion with members of the Reporting
department, we learn that a need has arisen to craft MDX queries for some new
analysis and reporting requirements. First, several requirements have been
identified to generate datasets, from the Adventure Works cube, to
support OLAP reports that management has requested. The client has implemented
the integrated Microsoft BI solution, and, in addition to using Analysis
Services as an OLAP data source, they use Reporting Services as an
enterprise reporting solution. The MDX we explore together, we are told, will
thus be adapted and extended for ultimate use within Reporting Services,
in multiple parameterized reports.
The requests relayed by the client representatives evidence
a need to present multidimensional data in a manner that we think might best be
served with the StripCalculatedMembers() function. Once our colleagues
provide an overview of the business requirements, and we conclude that StripCalculatedMembers()
is likely to be a key component of the option we offer, we provide the
details about the function and its use, much as we have done in the earlier
sections of this article. We convince the authors that they might best become
familiar with the StripCalculatedMembers() function by examining an
introductory example, where we employ the function to generate a straightforward
group of the members, excluding calculated members, that are contained
within the scope of a specified set expression, based upon an example we
provided in an earlier session where we demonstrated a means of generating a
simple set of base and calculated members in results dataset.
Procedure: Use the StripCalculatedMembers()
Function to Generate a Simple Set of Members (Calculated Members Excluded) in a
Results Dataset
Lets construct a simple query to provide a conceptual
starting point for illustrating the use of the StripCalculatedMembers() function. We will leverage an example we encountered in Set
Functions: The AddCalculatedMembers() Function, using it first to generate
a basic data set that displays a single base member that we
request, along with all calculated members that share the same parent, [Measures].
Once we established a dataset containing both base and calculated
members, we will demonstrate how we might use StripCalculatedMembers() to
remove calculated members from that set.
To reiterate the initial scenario, the client
representatives have told us that they would like to see the base member
/ measure Internet Sales Amount, alongside all calculated members
whose parent is [Measures] (in effect, practically all calculated
members within their cube). Within the scope of our current visit, they
add another requirement: once we have a working query that retrieves the
desired base measure, together with all calculated members that
exist as siblings to the desired measure, our colleagues wish to see how we
might modify the query to once again remove the calculated members,
leaving only the base measure preferably in a way that requires minimal
syntax modification, so as to easily support parameterization of an include
or exclude state within a targeted client application, Reporting Services.
Our
client colleagues present the following specifics for this initial
illustration: they wish to design and build a query that presents Internet
Sales Amount, alongside all calculated measures, for each of
the Customer Countries purchasing Adventure Works products in
operating Calendar Years 2003 and 2004. They tell us that they
want Internet Sales Amount and the calculated members to appear
as columns and the Customer Countries to appear as rows. Moreover, they
wish to break out the values for each of the two Calendar Years,
affording consumers the capability to easily compare, one above the other, a
given Customers values for each year. In effect, they wish to see Internet
Sales Amount and all calculated members presented by Customer
Country and subanalyzed by Calendar Year (for each of 2003 and
2004).
The
new twist in the original requirement, as our colleagues have told us, is that,
in addition to being able to generate a dataset containing all calculated
members, as noted on our previous visit, they then need to be able to
strip the calculated members out - in a manner that will lend itself to
on off parameterization. The initial dataset we generate will contain the
desired base member, along with all calculated members
that share the same parent, [Measures]. With this as a starting point,
we will be able to show the concepts behind using the StripCalculatedMembers()
function. Once we have accomplished our immediate goal in this section, we
will further evolve these concepts in meeting another business requirement in
the procedure that follows it.
1.
Type (or cut
and paste) the following query into the Query pane:
-- MDX065-1: Basic Use of ADDCALCULATEDMEMBERS() Function (from MDX064-1)
SELECT
ADDCALCULATEDMEMBERS({[Measures].[Internet Sales Amount]})
ON AXIS (0),
NON EMPTY
CROSSJOIN(
{[Customer].[Customer Geography].[Country].MEMBERS},
{[Date].[Calendar Year].[CY 2003]:[Date].[Calendar Year].[CY 2004]}
)
ON AXIS (1)
FROM
[Adventure Works]
The Query pane appears,
with our input, as shown in Illustration 2.
Illustration 2: Our Initial Query in the Query Pane ...
The above query sets the stage for our practice with the use
of StripCalculatedMembers(), and certainly accomplishes the basic
objective of illustrating, in the simplest manner, how it works. The idea is
to generate a dataset to activate the concepts in the minds of our client
colleagues.
2.
Execute the
query by clicking the Execute button in the toolbar, as depicted in Illustration
3.
Illustration 3: Click Execute to Run the Query...
The Results pane is populated by Analysis
Services, and a dataset similar to that partially shown in Illustration
4, appears.
Illustration 4: Results Dataset Single Member with
Sibling Calculated Members Scenario (Partial View)
In the returned dataset, we see all members of the Country
level of the Customer dimension (Customer Geography
hierarchy). We have juxtaposed the crossjoin of each Country with each
of Calendar Years 2003 and 2004 (generating them with the Range (:)
operator) with the associated Internet Sales Amount base member, and
all sibling calculated member, values.
Per the client request, our
next step is to generate, from the current data, a dataset containing only the
single base member of interest, Internet Sales Amount. For this
we will employ the StripCalculatedMembers() function.
4.
Replace the
commented line atop the query with the following text:
-- MDX065-2: Basic Use of STRIPCALCULATEDMEMBERS() Function
5.
Place the cursor
within the query one line above the AddCalculatedMembers keyword.
6.
Press the ENTER
key twice create an additional couple of empty lines above the AddCalculatedMembers
keyword.
7.
Type the
following into the space a line above the AddCalculatedMembers keyword:
STRIPCALCULATEDMEMBERS(
8.
Type an
additional right parenthesis ( ) ) to the immediate right of the line
containing the AddCalculatedMembers function.
The Query pane appears,
with our changes circled, as depicted in Illustration 5 (relevant
portions of the query only).
Illustration 5: Relevant Portions of the Query in the
Query Pane (Modifications Circled) ...
The above query sets the stage for our practice with the use
of StripCalculatedMembers(), and certainly accomplishes the basic
objective of illustrating, in the simplest manner, how it works. The idea,
again, is to generate a dataset to activate the concepts in the minds of our
client colleagues.
9.
Execute the
query by clicking the Execute button in the toolbar, as we did earlier.
The Results pane is populated by Analysis
Services, and a dataset similar to that shown in Illustration 6,
appears.
Illustration 6: Results Dataset StripCalculatedMembers()
in Action ...
In the returned dataset, we see the same axes as before,
with the obvious difference lying in the measure column. All that appears now
is the Internet Sales Amount base member; all sibling calculated
members have disappeared. The resulting dataset provides an excellent
demonstration of the action of the StripCalculatedMembers() function,
which we have used to enclose an AddCalculatedMembers() component whose
output we have verified independently in the steps preceding the addition of StripCalculatedMembers().
Having demonstrated the workings of the two functions in this fashion helps us
to show our client colleagues that we have, within the current dataset query,
the mechanics for parameterization with respect to the StripCalculatedMembers()
function we can make it possible to provide a parameter that enables /
disables the function at runtime, perhaps with a parameter picklist of, say, include
or exclude options for calculated members.
10.
Select File
-> Save MDX065-001 As ..., name the file MDX065-002,
and place it in a meaningful location.
Our
developer / author colleagues express satisfaction with the contextual backdrop
we have established for introducing the StripCalculatedMembers()
function. We will employ the function again in our next steps, this time
generating our all members dataset with another previously presented example,
before once again eliminating calculated members from the set via the StripCalculatedMembers()
function.
Procedure: Use the StripCalculatedMembers()
Function to Generate Another Set of Members (Calculated Members Excluded) in a Filtered
Results Dataset
In Set Functions: The .AllMembers Function, we examined a function in the
MDX toolset whose purpose is to return a set composed of all members within a specified
dimensional level or hierarchy. The set returned
includes all calculated members contained
within the specified level or
hierarchy, so, depending upon the set
specified in the function, the data retrieved is similar to that retrieved through
the simple employment (such as that we saw in our first practice example above)
of the AddCalculatedMembers()
function.
In one of the practice examples we undertook, we described
a client requirement to construct a query that presents all measures (including
calculated members / measures) for each of the Product
Categories offered by the organization for their current and prior year (2004
and 2003, respectively), presented by Product Category, and
subanalyzed by Customer Country. Our colleagues explain that management
is attempting to perform analysis upon the Categories, specifically
within the context of the contribution of each Customer Country toward
the totals for each Category value. .
Because
the initial business requirement entailed working with all measures
(all members of the Measure dimension, as it were), we explained that .AllMembers
promised to be useful in generating the desired presentation. We confirmed
our understanding of the stated needs, and then set out to craft a query that
relied upon .AllMembers, in conjunction with a couple of other
MDX functions, to meet the business need. We repeat these steps in this
section, from which we will derive a set comprising all members
within the Measures dimension, including calculated members.
1.
Select File
--> New from the main menu, once again.
2.
Select Query
with Current Connection from the cascading menu that appears next, as
depicted in Illustration 7.
Illustration 7: Create a New Query with the Current
Connection ...
A new
tab, with a connection to the Adventure Works cube (we can see it listed
in the selector of the Metadata pane, as expected) appears in the
Query pane.
3.
Type (or cut
and paste) the following query into the Query pane:
3. Type (or cut and paste) the following query into the Query pane:
-- MDX065-3: Basic Use of .ALLMEMBERS Function; Measure Dimension
-- ( from MDX061-2)
SELECT
CROSSJOIN(
{[Measures].ALLMEMBERS},
{[Date].[Calendar Year].[CY 2004]:[Date].[Calendar Year].[CY 2003]})
ON AXIS (0),
CROSSJOIN(
{[Product].[Product Categories].CHILDREN},
[Customer].[Country].[Country].MEMBERS)
ON AXIS (1)
FROM
[Adventure Works]
The Query pane appears,
with our input, as shown in Illustration 8.
Illustration 8: Our Second Query in the Query Pane ...
4.
Execute the
query by clicking the Execute button in the toolbar.
The Results pane is, once again, populated by
Analysis Services. This time, the dataset partially depicted in Illustration
9 appears.
Illustration 9: Results Dataset .AllMembers Applied to
Deliver All Measures (Partial View)
In the returned dataset, we see the juxtaposed Years
(2003 and 2004), which we generate via the MDX Range
operator (:) and all measures within the cube including calculated
members / measures, which we deliver via the .AllMembers
function. Moreover, we leverage the .Children and .Members
functions to specify a row axis containing Product Categories, which we
further subanalyze by Customer Country. We perform the desired
juxtapositions within the query via the CrossJoin() function.
Of primary focus within this practice example is our use of
the .AllMembers function, in conjunction with these other functions, to
return all measures in effect, all members of the Measures dimension.
(We can easily verify operation by observing that all measures within
the cube appear within the dataset we can scroll over to see that all measures
are present.) In this example, we can also see another characteristic of the
behavior of .AllMembers in cases where a dimension contains only
a single visible hierarchy: in such cases, the hierarchy can be
referenced by the hierarchy name or the dimension name, because
the dimension name in such a scenario is resolved to its only visible hierarchy.
In our immediate example, Measures.AllMembers is a valid MDX expression
because it resolves to the only hierarchy in the Measures dimension.
5.
Select File
-> Save MDXQuery2.mdx As ..., name the file MDX065-003.mdx,
and place it in the same location used to store the earlier query.
Per the client request, our
next step is to generate a dataset containing only the base members of the
Measures dimension. For this we will employ the StripCalculatedMembers()
function.
6.
Replace the
commented line atop the query with the following text:
-- MDX065-4: Another Basic Use of STRIPCALCULATEDMEMBERS() Function
7.
Place the
cursor within the query one line above {[Measures].ALLMEMBERS} (currently the fourth line from the top in the
query), underneath the line containing the first CROSSJOIN keyword).
8.
Press the ENTER
key twice create an additional couple of empty lines between the lines
containing CROSSJOIN( and {[Measures].ALLMEMBERS}.
9.
Type the
following into the space a line above {[Measures].ALLMEMBERS}.
STRIPCALCULATEDMEMBERS(
10.
Type an
additional right parenthesis ( ) )to the immediate right of {[Measures].ALLMEMBERS} (between {[Measures].ALLMEMBERS} and the comma ( , ) that
appears to its right).
The relevant portion of the Query
pane appears, with our changes circled, as shown in Illustration 10.
Illustration 10: Relevant Portions of the Query in the
Query Pane (Modifications Circled) ...
The above modifications set the stage for our practice with the
use of StripCalculatedMembers(), this time within the context of calculated
members being exposed via the .AllMembers function.
11.
Execute the
query by clicking the Execute button in the toolbar, as we did earlier.
The Results pane is populated by Analysis
Services, and a dataset similar to that partially depicted in Illustration
11, appears.
Illustration 11: Results Dataset
StripCalculatedMembers() in Action ... (Partial Dataset View)
In the returned dataset, we see the same axes as before,
with the obvious difference lying in the measure columns. All that appears now
are the base members of the Measures dimension; all calculated
members have disappeared. The resulting dataset provides another demonstration
of the action of the StripCalculatedMembers() function, which we have
used to enclose an .AllMembers component whose output we have verified
independently in the steps preceding the addition of StripCalculatedMembers().
Having demonstrated the workings of the two functions in
this fashion once again helps us to show our client colleagues that we have,
within the current dataset query, established the mechanics for
parameterization with respect to the StripCalculatedMembers() function.
As we noted in our first practice example above (where we based our stripping
action upon a set of all Measure members which we had derived via the AddCalculatedMembers()
function), we can make it possible to provide a parameter that enables /
disables the function at runtime, again perhaps with a parameter picklist of,
say, include or exclude options for calculated members.
12.
Select File
-> Save MDX065-003.mdx As ..., name the file MDX065-004,
and place it in a meaningful location.
Our
client colleagues express satisfaction with the results, and confirm their
understanding of the operation of the StripCalculatedMembers() function
within the context we have presented in both practice exercises. We suggest to the
team that, in addition to parameterization of a show / dont show calculated
members option and other possibilities, the Years (beginning and
ending, for that matter) might be parameterized, that we might build in the
capability to swap crossjoined members, and that we might add other
capabilities within the ultimate reporting dataset query. Suffice it to say
that, assuming a thorough knowledge of the various layers of the Microsoft
integrated BI solution, one can obtain many powerful capabilities and features,
and knowing where to put the intelligence within the sometimes multiple choices
can mean highly tuned performance and effective solutions for consumers
throughout our organizations. For more of my observations on this subject see Multi-Layered Business Solutions ... Require
Multi-Layered Architects.
13.
Select File
-> Exit to leave the SQL Server Management Studio, when ready.
Summary ...
In
this article, we explored the MDX StripCalculatedMembers() function,
whose general purpose is to retrieve the members of a specified set,
after removing any calculated members.
We
examined the syntax involved with StripCalculatedMembers(), and then
undertook a couple of illustrative practice examples of uses for the function,
generating queries that capitalized upon its capabilities. Throughout our
practice session, we briefly discussed the results datasets we obtained from
each of the queries we constructed, as well as extending our discussion to
other possible options and uses for the concepts we exposed.
»
See All Articles by Columnist William E. Pearson, III
Discuss this article in the MSSQL Server 2000 Analysis Services and MDX Topics Forum.