This is an introductory look at MDX presented by Nathan Peterson of Solid Quality Mentors
Every developer should be able to write the MDX needed to create Key Performance Indicators (KPIs) to meet business requirements. This short session will give you a solid introduction to the language, so that you can start using its power to give your business the information it needs.
You will learn how to:
* Think multi-dimensionally to better understand how cube data works
* Use MDX, the query language for Analysis Services
* Create Named Sets and Calculated Members with MDX to meet business needs
SQL Database Design For Developers at php[tek] 2024
What All Microsoft BI Developers Need to Know About MDX
1. 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
2. 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
3. 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.
4. 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.
5. Sample calculated member
with member
measures.[Last Year Sales Amount]
as
(
measures.[Sales Amount],
ParallelPeriod
(
[Date].[Calendar].[Calendar Year],
1,
[Date].[Calendar].CurrentMember
)
)
6. Sample named set
with
set [Top 5 Products]
as
topcount
(
[Product].[Product].Members,
5,
Measures.[Internet Sales Amount]
)
7. Comparing MDX to SQL
From
SQL selects from a table.
MDX selects from a cube.
Dimensionality
SQL returns one or more columns and 0 or more rows.
MDX can return data for 0, 1, 2, 3 or more axes.
Where
SQL has a filter.
MDX has a slicer.
8. 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]
)
10. 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]
)
11. 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
12. 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.
13. 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]
14. 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]
15. 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.
19. 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]
20. 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
22. 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.
23. 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]
)
24. 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]
}
)
25. 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.
26. 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]
28. 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]
30. 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).
31. 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.
32. 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.
34. 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]
35. Functions – All in the Family
Parent
Children, FirstChild, LastChild
Descendants
Ancestor, Ascendants
Siblings, FirstSibling, LastSibling
Cousin
36. 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]
37. 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
38. Example of set multiplication
These two sets are equivalent.
[Date].[Fiscal].[Month].members
*
[Product].[Product].members
Crossjoin
(
[Date].[Fiscal].[Month].members,
[Product].[Product].members
)
39. 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.
40. 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]
41. 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
)
)
42. 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]
43. 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]
44. 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]
45. Additional topics – if there’s time
Dealing with exceptions
String manipulation
Generate
Recursion
46. 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
47. 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)
+ "]"
)
48. 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]
) ) )
49. 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
)