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.