You are on page 1of 51

What All Microsoft BI Developers

Need to Know About MDX


Speaker: Nathan Peterson
Solid Quality Mentors

Silicon Valley SQL Server User Group


January 19, 2009

Mark Ginnebaugh, User Group Leader,


mark@designmind.com
Nathan Peterson

 Solid Quality Mentors


 Currently working on an Analysis Services project
for the US Army

 Lead developer of a local cube generating utility


called CubeSlice
What do all developers need to know about
MDX?

 You should be able to:


 Create and debug Calculated Members.
 Create and debug Named Sets.

 What you need to know to accomplish this:


 Understand MDX Concepts.
 Learn MDX Syntax.

 Learn some MDX functions.

 Learn some practical applications of MDX.


What Is MDX?

 Multi-Dimensional eXpressions
 SQL is used for relational queries, while MDX is used
for multidimensional queries.
 Calculated members allow you to incorporate
multidimensional logic into your cube.
 Named sets allow you to pre-define dynamic groups
of members to be displayed on columns or rows.
Sample calculated member

with member
measures.[Last Year Sales Amount]
as
(
measures.[Sales Amount],
ParallelPeriod
(
[Date].[Calendar].[Calendar Year],
1,
[Date].[Calendar].CurrentMember
)
)
Sample named set

with
set [Top 5 Products]
as
topcount
(
[Product].[Product].Members,
5,
Measures.[Internet Sales Amount]
)
Comparing MDX to SQL

 From
 SQLselects from a table.
 MDX selects from a cube.

 Dimensionality
 SQLreturns one or more columns and 0 or more rows.
 MDX can return data for 0, 1, 2, 3 or more axes.

 Where
 SQLhas a filter.
 MDX has a slicer.
MDX query with two axes and two slicers

select
Measures.AllMembers on columns,
[Date].[Calendar].&[2003].Children on rows
from [Adventure Works]
where
(
[Customer].[Customer Geography].[France],
[Product].[Product Categories].[Bikes]
)
Dimensions and Measures
Same query, using axis numbers instead of axis
names

select
Measures.AllMembers on 0,
[Date].[Calendar].&[2003].Children on 1
from [Adventure Works]
where
(
[Customer].[Customer Geography].[France],
[Product].[Product Categories].[Bikes]
)
Using MDX requires multidimensional thinking

 In a cube
 Dimensions have hierarchies
 Hierarchies have levels

 Levels have members

 In a cellset
 Each axis contains a set
 Each set consists of a group of members or a group of
tuples
 Tuples have members from different hierarchies
Multidimensional thinking – Where are you?

 Every member is in a level.


 Every level is in a hierarchy.
 Every hierarchy is a part of a dimension.
 For every cell of the cellset, there’s (almost) always
a Current Member for each hierarchy.
 The Current Member may be set from the column,
the row, the slicer, or the default member.
Create a set by listing members

 The simplest set is a list of members.


 The boundaries of the set are indicated with curly
braces {}.
select
{
[Product].[Category].[All Products],
[Product].[Category].[Accessories],
[Product].[Category].[Bikes],
[Product].[Category].[Clothing],
[Product].[Category].[Components]
} on 0
from [Adventure Works]
Create a set with a function

 There are many MDX functions that create sets.


 This query uses the .Members function to return all
the members from a hierarchy – and gives the same
result as the previous query.
 You don’t have to use {} when you create a set with
a function.
select
[Product].[Category].Members on 0
from [Adventure Works]
Tuples

 Each cell in a cellset shows data for one particular


member from each hierarchy.
 A tuple is a way of specifying which member should
be used from each of the hierarchies.
 Tuples are written like points in a geometric grid:
 (6,3) identifies point 6 on the x-axis and point 3 on the
y-axis.
 ([2009],[US],[Bikes],[Internet Sales Amount]) identifies
Internet Sales for Bikes in the US in 2009.
2 Dimensional Tuple

6
5 2 Dimensional Tuple
4
3
2 (6, 2)
1

1 2 3 4 5 6 7 8
Create a set by listing tuples

select
{
(
[Date].[Calendar Year].&[2002],
[Product].[Category].[Accessories]
),
(
[Date].[Calendar Year].&[2002],
[Product].[Category].[Bikes]
),
(
[Date].[Calendar Year].&[2003],
[Product].[Category].[Accessories]
),
(
[Date].[Calendar Year].&[2003],
[Product].[Category].[Bikes]
)
}
on 0
from [Adventure Works]
Listing Tuples

[Accessories]
[Clothing] 2 Dimensional Tuple
[Touring Bikes]
[Road Bikes]
([2006], [Mountain Bikes])
[Mountain Bikes]
[All Products]

2 2 2 2 2 2 2 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8
Create a set of tuples by multiplying two sets of
members

select
{
[Date].[Calendar Year].&[2002],
[Date].[Calendar Year].&[2003]
}
*
{
[Product].[Category].[Accessories],
[Product].[Category].[Bikes]
}
on 0
from [Adventure Works]
3 Dimensional Tuple

[Accessories]
[Clothing] 3 Dimensional Tuple
Difficult to Show in 3 Axes –
[Touring Bikes] Where to place the point?
[Road Bikes]
([2006], [Mountain Bikes], [Red])
[Mountain Bikes]
[All Products]

[Red]
[Blue]
2 2 2 2 2 2 2 2
[Pink] 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8
3 Dimensional Tuple
Combining 2 Hierarchies on 1 Axis

([Blue], [Road Bikes])


([Red], [Road Bikes]) 3 Dimensional Tuple
([Blue], [Mountain Bikes])
([Red], [Mountain Bikes])

([Blue], [All Products])


([2006], [Mountain Bikes], [Red])
([Red], [All Products])

2 2 2 2 2 2 2 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8
The Where clause

 The Where clause is an optional part of an MDX


query.
 The Where clause is a slicer, not a filter.
 You can’t use the Where clause for limiting the value to
a threshold (Sales over $10,000).
 Use the Filter function for filtering.

 The Where clause often looks like a tuple and


actually is a tuple – but it doesn’t have to be.
Where clause using a tuple – one member from
each referenced hierarchy

select
Measures.[Internet Sales Amount] on 0
from [Adventure Works]
where
(
[Customer].[Customer Geography].[France],
[Product].[Product Categories].[Bikes]
)
Where clause with slicing on multiple members
from one hierarchy

select
Measures.[Internet Sales Amount] on 0
from [Adventure Works]
where
(
[Customer].[Customer Geography].[France],
{
[Product].[Product Categories].[Bikes],
[Product].[Product Categories].[Clothing]
}
)
The With clause

 The With clause is used for creating both calculated


members and named sets.
 These calculated members and named sets are only
valid for the life of the query.
 You can also create calculated members and named
sets that are persistent:
 Lasting
for the life of a session.
 Created permanently in the cube.
Creating calculated member in the With clause

with
member Measures.[Average Internet Sales]
as
[Measures].[Internet Sales Amount]
/
[Measures].[Internet Order Count],
format_string = "currency"
select
{Measures.[Average Internet Sales]} on 0
from [Adventure Works]
Members, Sets, Tuples

([Blue], [Road Bikes])


([Red], [Road Bikes]) Members, Sets, Tuples
([Blue], [Mountain Bikes])
Set of
(Partial) ([Red], [Mountain Bikes])
Tuples
([Blue], [All Products])
([2006], [Mountain Bikes], [Red])
([Red], [All Products])
(Partial) Tuple
Member

2 2 2 2 2 2 2 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8

Set of Members
Creating named set in the With clause

with
set [Products - High Selling on Internet]
as
filter
(
[Product].[Product].[Product].Members,
[Measures].[Internet Sales Amount]
> 50000
)
select
{Measures.[Internet Sales Amount]} on 0,
[Products - High Selling on Internet] on 1
from [Adventure Works]
Full Tuple

([Blue], [Road Bikes]) ([2006], [Mountain Bikes], [Red], [All


([Red], [Road Bikes]) Promotions], [All Gender],
[Measures].[Reseller Sales Amount],
([Blue], [Mountain Bikes])
etc…)
([Red], [Mountain Bikes])
([Blue], [All Products])
([Red], [All Products])

2 2 2 2 2 2 2 2
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
1 2 3 4 5 6 7 8
MDX Punctuation

 Use {} for sets.


 Use () for tuples.
 Use [] for names of cubes, dimensions, hierarchies,
levels, and members.
 Use commas all over the place (except not between
multiple calculated members or named sets defined
in the same query).
Where to write your MDX

 In a client application like PerformancePoint, which


allows you to write code for calculated measures
and sets.
 In a query editor like the SQL Server Management
Studio.
 In the MDX Script of a cube.
TIP: It’s often easier to write the code in a query editor
first and then put it into the MDX Script.
Writing MDX for a KPI

 You can write MDX to create the values for a KPI,


whether you’re working with Analysis Services KPIs
or PerformancePoint Services KPIs.
 For both tools, it’s easier to create calculated
members in the MDX script for the values first.
 TIP: When building KPIs in the BIDS, use a template
for assigning the Status and the Trend.
Functions – Navigating within a level

 PrevMember
 NextMember
 Lag()
 Lead()
Examples of navigating in a level

 Navigation functions are often used with Dates.


 Note: PrevMember, Lag(1), and Lead(-1) all return
the same member.
[1997].PrevMember
[1996]
[March 2010].NextMember [April 2010]
[10 April 2009].Lag(2) [8 April
2009]
[December 2009].Lead(12) [December 2010]
Functions – All in the Family

 Parent
 Children, FirstChild, LastChild
 Descendants
 Ancestor, Ascendants
 Siblings, FirstSibling, LastSibling
 Cousin
Examples of family functions

 Some of the family functions return individual


members, while other return sets.
 If a function returns an individual member, you can
use another function with it.
[Mar 1997].Parent [1997]
[Q1 2009].Children [Jan 09]:[Mar
09]
[2009].FirstChild [Q1 2009]
Descendants([2009], 2) [Jan 09]:[Dec 09]
Descendants([2009],[Date])[1Jan09]:[31Dec09]
Ancestor([Mar 2008], 3) [2008]
FirstSibling([Mar 2007]) [Jan 2007]
Functions – Multiplying, adding, subtracting,
intersecting sets

 Set multiplication, addition, and subtractions can


be indicated with mathematical symbols or with
functions.

Multiplication * Crossjoin
Addition + Union
Subtraction - Except
Intersection Intersect
Example of set multiplication

 These two sets are equivalent.

[Date].[Fiscal].[Month].members
*
[Product].[Product].members

Crossjoin
(
[Date].[Fiscal].[Month].members,
[Product].[Product].members
)
Practical Applications of MDX

 Comparing with a previous time period.


 Comparing with the same time period in the
previous year.
 Year-To-Date.
 Rolling Average.
 Percent contribution.
Comparing with a previous time period

with member Measures.[Last Month Sales]


as
(
Measures.[Internet Sales Amount],
[Date].[Calendar].PrevMember
)
select
{
Measures.[Internet Sales Amount],
Measures.[Last Month Sales]
} on 0,
[Date].[Calendar].[Month].members on 1
from [Adventure Works]
Comparing with the same period in the previous
year

with member
measures.[Last Year Sales Amount]
as
(
measures.[Sales Amount],
ParallelPeriod
(
[Date].[Calendar].[Calendar Year],
1,
[Date].[Calendar].CurrentMember
)
)
Year--To
Year To--Date

with
member measures.[YTD Sales]
as
sum
(
ytd([Date].[Calendar].CurrentMember),
Measures.[Internet Sales Amount]
)
select
{
Measures.[Internet Sales Amount],
Measures.[YTD Sales]
} on 0,
[Date].[Calendar].[Month].members on 1
from [Adventure Works]
Rolling Average

With
member measures.[Previous 6 Month Rolling AVG]
as
sum
(
[Date].[Calendar].lag(6):
[Date].[Calendar].lag(1),
Measures.[Internet Sales Amount]
) / 6
select
{
Measures.[Internet Sales Amount],
Measures.[Previous 6 Month Rolling AVG]
} on 0,
[Date].[Calendar].[Month].members on 1
from [Adventure Works]
Percent Contribution

With member Measures.[Percent of Parent Sales]


as
Measures.[Internet Sales Amount]
/
(
Measures.[Internet Sales Amount],
[Product].[Product Categories].Parent
)
select
{
Measures.[Internet Sales Amount],
Measures.[Percent of Parent Sales]
} on 0,
[Product].[Product Categories]. members on 1
from [Adventure Works]
Additional topics – if there’s time

 Dealing with exceptions


 String manipulation
 Generate
 Recursion
Dealing with exceptions

 A calculation needs to be valid everywhere


with
member [Measures].[% Change # of Customers]
as
case
when [Date].[Fiscal].CurrentMember.Level.Ordinal = 0 then "NA”
when [Date].[Fiscal].CurrentMember.Level.Ordinal = 5 then Null
when isempty
(
([Date].[Fiscal].CurrentMember.PrevMember, [Measures].[Customer Count])
) then null
else
(
([Date].[Fiscal].CurrentMember, [Measures].[Customer Count])
-
([Date].[Fiscal].PrevMember, [Measures].[Customer Count])
)
/
([Date].[Fiscal].PrevMember,[Measures].[Customer Count])
end
Functions - String manipulation

 Turning the current date into a member reference

Strtomember
(
"[Date].[Fiscal].[Date].&["
+ cstr(year(now()) - 6)
+ right("0" + cstr(month(now())), 2)
+ right("0" + cstr(day(now())), 2)
+ "]"
)
The Generate function

 What are the five top products most purchased by


people living in my top five cities?
generate
(
topcount
(
[Customer].[Customer Geography].[City].members,
5,
[Measures].[Internet Sales Amount]
),
crossjoin
(
[Customer].[Customer Geography].CurrentMember,
topcount
(
[Product].[Product].[Product].members,
5,
[Measures].[Internet Sales Amount]
) ) )
Recursion

 Finding the most recent purchase

with
member measures.[Most Recent Purchase]
as
iif
(
[Measures].[Internet Sales Amount] > 0,
[Measures].[Internet Sales Amount],
[Date].[Calendar].PrevMember
)
Thank you
 npeterson@solidq.com

 http://www.databasejournal.com/article.php/1459531/

 http://msdn.microsoft.com/en-us/library/ms145970.aspx

 http://www.sqlserveranalysisservices.com

 http://www.ssas-info.com/analysis-services-faq/27-mdx

 http://www.mosha.com/msolap/mdx.htm

 http://cwebbbi.spaces.live.com
To learn more or inquire about speaking opportunities, please contact:

Mark Ginnebaugh, User Group Leader


mark@designmind.com

You might also like