Intro to Mdx Aso

126
#Kscope Intro to MDX + ASO Gary Crisci Oracle Ace

Transcript of Intro to Mdx Aso

Page 1: Intro to Mdx Aso

#Kscope

Intro to MDX + ASO

Gary Crisci

Oracle Ace

Page 2: Intro to Mdx Aso

#Kscope

Developing Essbase Applications

● Like the best, most advanced Essbase conference there ever could be

● Advanced content● Good practices● Written by some of the most well

known Essbase developers● Source code at

www.developingessbasebook.com● You should buy it

Page 3: Intro to Mdx Aso

#Kscope

What is ASO?

● ASO stands for Aggregate Storage Option● Essbase applications have two distinct

architecture/storage options● Aggregate Storage (ASO)● Block Storage (BSO)

● ASO was introduced in version 7● Initially ASO was seen as an alternative to large block

storage applications with sparse data sets● With enhancements over the last few releases, in many

cases, ASO is now the default storage option choice for new applications

Page 4: Intro to Mdx Aso

#Kscope

Differences Between ASO and BSO

● Aggregate storage applications store data in tablespaces.

● Each application directory contains directories for four tablespaces:

● default: Contains database data structure and database values (After data is loaded, the tablespace location cannot be changed.)

● log: contains a binary transactional log of all the updates that are made in the default tablespace

● metadata: contains information about the file locations, files, and objects contained in the database

● temp: Provides a temporary workspace to be used during operations such as data loads, aggregations, and retrievals

Page 5: Intro to Mdx Aso

#Kscope

Differences Between ASO and BSO

BSO has Dense

and Sparse

dimensions

ASO has Dynamic

and Stored

hierarchies

Page 6: Intro to Mdx Aso

#Kscope

ASO Hierarchies

Stored or Dynamic• Different concept than BSO

Cross use of terms causes confusion• “Everything in ASO is Dynamic”• “For best performance make

everything stored”

Page 7: Intro to Mdx Aso

#Kscope

Stored vs. Dynamic

Let’s clarifyA level 0 member with

no formula, even though it is in a

dynamic hierarchy, is still a stored member.

All level 0 members that do not have formulas are

stored in ASO.

Upper level members are all "dynamic".

Upper level members of dynamic hierarchies are

pure dynamic (i.e. calculated on retrieval).

Upper level members of stored hierarchies are

candidates to have their values pre-aggregated and stored in a view.

Page 8: Intro to Mdx Aso

#Kscope

Stored Hierarchies● Stored hierarchies are the default hierarchy setting and generally

best performing. ● Whenever possible, hierarchies should be set to Stored.

● The limitations of stored hierarchies are that all members must be set to (+ or ~) for the consolidation operator.

● If the consolidation operator is set to (~), the parent member must be set to Label Only.

● You cannot have members with member formulas in a stored hierarchy, and you cannot have shared members in a stored hierarchy (unless the stored hierarchy is within a multiple hierarchies enabled dimension).

● There are also two limitations on label only members. ● 1) All dimension members at the same level as the member must be

label only and ● 2) the parents of the member must be label only.

Page 9: Intro to Mdx Aso

#Kscope

Stored Hierarchy - Label Only

● Invalid

● Valid

Page 10: Intro to Mdx Aso

#Kscope

Dynamic Hierarchies

The order in which members and formulas are evaluated is defined by the solve order property.

To evaluate a dynamic hierarchy, Essbase calculates, rather than aggregates, the members and formulas

When we talk about dynamic hierarchies, we are talking about the way Essbase stores and optimizes the data

Page 11: Intro to Mdx Aso

#Kscope

Dynamic Hierarchies

● At the time of retrieval, Essbase calculates the required member combinations and calculates any required outline member formulas.

● Because dynamic hierarchies are calculated, the data retrieval time may be longer than for data retrieved from stored hierarchies.

● However, when you design your database, dynamic hierarchies provide the following advantages:

● 1) They can contain any consolidation operator.● (+, -, *, /, %, ~)

● (^) Not Supported● 2) They can have formulas.

Page 12: Intro to Mdx Aso

#Kscope

Stored vs. Dynamic

For best query performance, try to make as many hierarchies stored as possible• Stored hierarchies

become candidates for pre-aggregation• Queries will be

much faster• Can leverage query

tracking to optimize aggregations

Page 13: Intro to Mdx Aso

#Kscope

Multiple Hierarchies

● Multiple hierarchies is a setting at the dimension level that allows for having both stored and dynamic hierarchies within the same dimension.

Page 14: Intro to Mdx Aso

#Kscope

Accounts Dimension and Members on Dynamic Hierarchies

In Block Storage applications, “Accounts” dimension, has added functionality.

• Accounts dimensions are enabled for Expense reporting, and Time Balancing.

Aggregate Storage applications do not support expense reporting.

• Can simulate with UDA and conditional MDX statements (CASE and/or IF).

ASO Account dimension supports Time Balancing

• There are limitations• Often will need to consider alternative approach

• MDX Time Balancing• Aggregating solutions using periodic balances instead of time balances

Page 15: Intro to Mdx Aso

#Kscope

•By default, it is also set as the compression dimension•This is

not always a good thing!

ASO Account dimensions are

dynamic

•ASO applications do support Solve Order. •Solve

Order works in conjunction with the MDX query language to determine calculation order when processing member formulas.

Aggregate storage applications do not support two-pass

calculations,

Accounts Dimension and Members on Dynamic Hierarchies

Page 16: Intro to Mdx Aso

#Kscope

Shared Members and Alternate Hierarchies

ASO has two methods to support alternate hierarchies

Use of an attribute

dimension

Hierarchy of shared

members.

Page 17: Intro to Mdx Aso

#Kscope

Shared Member and Alternate Hierarchies

● The alternate hierarchy has shared members that refer to non-shared members of previous hierarchies in the outline.

● The shared members roll up according to a different hierarchy from the non-shared members to which they refer.

● Shared members on dynamic hierarchies can have formulas.

Page 18: Intro to Mdx Aso

#Kscope

Shared Member and Alternate Hierarchies

● The following restrictions apply when creating alternate hierarchies in aggregate storage outlines:

● The nonshared instance of the member must occur in the outline before any shared instances of the member.

● The first hierarchy in a dimension where multiple hierarchies are enabled cannot contain a shared member.

● Stored hierarchy dimensions cannot have shared members. ● Stored hierarchies within a multiple hierarchies dimension can have shared

members.● To ensure that values are not double-counted, a stored hierarchy

cannot contain multiple copies of the same shared member.● Nonshared instances of a member must be in the same dimension as

the shared member (same for block storage outlines).● A stored hierarchy cannot contain a nonshared instance and a shared

instance of the same member.● A stored hierarchy can contain a shared instance of a dynamic

hierarchy member only if the dynamic hierarchy member is a level 0 member without a formula.

Page 19: Intro to Mdx Aso

#Kscope

Attribute Dimensions● Attribute dimensions in aggregate storage

databases:● Only the addition (+) consolidation operator is available for

attribute dimensions.● For a given attribute dimension, all associations must be

with one level of the base dimension. ● The following restrictions apply to attribute associations:

● Level 0: You can associate attributes with any level 0 member of a dynamic or stored hierarchy that does not have a formula.

● Non-level 0: You can associate attributes only to upper level members in the primary stored hierarchy.

Page 20: Intro to Mdx Aso

#Kscope

Attribute Dimensions

Essbase considers queries on attribute dimensions when using query tracking• May include attribute dimension

members in aggregate view selections.

Page 21: Intro to Mdx Aso

#Kscope

Calculation Differences

Page 22: Intro to Mdx Aso

#Kscope

Database Calculation● Database calculations are done in a block storage application by

executing calculation scripts, as well as member formulas, and outline consolidation operators.

● The ability to materialize data via MDX scripts has been recently introduced in v 11.1.2

● ASO database calculations are based on outline operators and member formulas.

● Aggregate storage applications are fully dynamic● data can be loaded into the database at level 0 and retrieved at upper

levels with calculated results being returned. ● To improve query performance, the database can be pre-

aggregated by defining aggregate views.

Page 23: Intro to Mdx Aso

#Kscope

Formulas

● BSO applications leverage Essbase calculation script functions

● Aggregate storage databases utilize MDX functions. ● There is no support for BSO functions in ASO, they must be

converted to MDX. ● Refer to the Essbase technical reference (

http://download.oracle.com/docs/cd/E12825_01/epm.111/esb_techref/frameset.htm?launch.htm

) ● Contents Section: MDX->Aggregate Storage and MDX->MDX

Outline Formulas.

Page 24: Intro to Mdx Aso

#Kscope

Attribute Calculations DimensionThe attribute calculations dimension in block storage applications

supports Sum, Count,

Min, Max, and Average by default.

The attribute calculations dimension in

aggregate storage

applications only supports

Sum.

Page 25: Intro to Mdx Aso

#Kscope

Data Load Differences

Page 26: Intro to Mdx Aso

#Kscope

Data Load Differences

Cells loaded through data loads• ASO : Only level 0 cells whose values do not depend on

formulas in the outline are loaded• BSO: Cells at all levels can be loaded (except Dynamic Calc

and Label Only members)

Update of database values• ASO: At the end of a data load, if an aggregation exists, the

values in the aggregation are recalculated• BSO: No automatic update of values. To update data values,

you must execute all necessary calculation scripts.

Page 27: Intro to Mdx Aso

#Kscope

Data Load Differences•ASO: The

loading of multiple data sources into aggregate storage databases is managed through temporary data load buffers.

•BSO: Not supported

Data load buffers

•ASO: When loading data, you can replace the contents of the database or the contents of all incremental data slices in the database.

•BSO: Not supported

Atomic replacement of the contents of

a database

Page 28: Intro to Mdx Aso

#Kscope

Data Load Differences

Data slices

•ASO: Databases can contain multiple slices of data. Data slices can be merged.

•BSO: Not supported

Dimension build for

shared memb

ers

•ASO: Full support for parent-child build method. Duplicate generation (DUPGEN) build method limited to building alternate hierarchies up to generation 2 (DUPGEN2).

•BSO: Support for all build methods

Page 29: Intro to Mdx Aso

#Kscope

Data Load Differences

Loading data mapped to

dates

ASO: In a date-time dimension, you can load

data into level-0 members using

supported date-format strings instead of member names.

BSO: Date-time dimension type is not

supported.

Page 30: Intro to Mdx Aso

#Kscope

Query Differences

Page 31: Intro to Mdx Aso

#Kscope

Query Differences

Report Writer

ASO: Supported, except for

commands related to sparsity and density of data

BSO: Fully supported

Spreadsheet Add-in

ASO: Supported, with limited ability to change data (write-

back)

BSO: Fully supported

Page 32: Intro to Mdx Aso

#Kscope

Query Differences

API•ASO: Supported•BSO: Supported

Export•ASO: Support with the following

restrictions:•Export of level 0 data only (no

upper-level export)•No columnar export

•BSO: Supported

Page 33: Intro to Mdx Aso

#Kscope

Query Differences

MDX queries

•ASO: Supported

•BSO: Supported

Queries on

attribute members that are

associated with

non-level 0

members

•ASO: Returns values for descendants of the non-level 0 member.

•BSO: Returns #MISSING for descendants of the non-level 0 member

Page 34: Intro to Mdx Aso

#Kscope

Query Differences

• ASO: A shared member automatically shares the attribute associations of its nonshared member

• BSO: A shared member does not share the attribute associations of its nonshared member

Queries on attribute members and shared members

• ASO: Not supported• BSO: Supported

Query logging

Page 35: Intro to Mdx Aso

#Kscope

Query Differences

Query performanceASO:

Considerations when querying data from a dimension that has multiple

hierarchies.

BSO: Hierarchies not relevant

Page 36: Intro to Mdx Aso

#Kscope

Feature Differences

Page 37: Intro to Mdx Aso

#Kscope

Feature Differences

Aliases

ASO: Supported

BSO: Supported

Currency conversion

ASO: Not supported

BSO: Supported

Page 38: Intro to Mdx Aso

#Kscope

Feature Differences

● Data mining● ASO: Not supported● BSO: Supported

● Hybrid analysis● ASO: Support with the following restriction:

● queries that contain a relational member and an Essbase member with a formula in the same query are not supported.

● For example, if California is a relational member, and the member Profit has a formula, the following report script returns an error:

● Jan California Profit !● BSO: Supported

Page 39: Intro to Mdx Aso

#Kscope

Feature Differences

Incremental data load

ASO: Supported

BSO: Supported

LROs

ASO: Not supported

BSO: Supported

Page 40: Intro to Mdx Aso

#Kscope

Feature Differences

Time balance reporting

Triggers

• ASO: Support with the following restrictions:• Skip Zeros is not supported• Time dimension must contain

at least one stored hierarchy• Shared members must be at

level zero• BSO: Supported

• ASO: After-update triggers supported

• BSO: On-update triggers and after-update triggers supported

Page 41: Intro to Mdx Aso

#Kscope

Feature Differences

Unicode• ASO: Supported• BSO: Supported

Variance reporting• ASO: Not supported

• Can work around with UDA and conditional MDX functions

• BSO: Supported

Page 42: Intro to Mdx Aso

#Kscope

Feature Differences

ASO: Supported

BSO: Not supported

Date-time dimension type and

linked attribute dimensions

BSO: Fully supported

ASO:• User write back

to level 0, via data slices, is supported

User ability to change data (write-

back)

Page 43: Intro to Mdx Aso

#Kscope

Case Study: Converting a large BSO application to ASO

Page 44: Intro to Mdx Aso

#Kscope

Existing BSO Model

Page 45: Intro to Mdx Aso

#Kscope

Existing BSO Model

26 GB database• 4 GB total .ind files• 22 GB total .pag files

Processing Window • 3 to 4 hours full overnight refresh• 1 hour intraday update

• Cube is offline during this window• Only update current year

Page 46: Intro to Mdx Aso

#Kscope

ASO Challenges● Large “Account” dimension with (+) and (–) operators

● To keep as is, would need to be Dynamic hierarchy● Too Slow!

● Only way to make it feasible is for Account dim to be Stored● Limited to (+) and (~) only

● “Account” dimension includes P&L and Balance Sheet● Balance Sheet values are time balanced

● Overall functionality has to be same as existing model● Query time, “look and feel”● Ability to query YTD values

Page 47: Intro to Mdx Aso

#Kscope

ASO Solutions● Convert Account dimension to Stored Hierarchy

● Remove “Account” tag● Set all members to (+)● Use accounting principles to convert accounts into Debit/Credit

format● Tag Debit /Credit members with UDA flags● Leverage load rules to “FLIP” values for tagged members upon data

load● Add a View dimension with two members

● Accounting View ● default load member with values in Debit/Credit format

● Management Reporting View● Calculated member that uses MDX formula to “FLIP” sign on Credit

members● Load Periodic Balance Sheet values

● Add a new “Beginning Balance” member to Time dimension● Train users to pull Balances using YTD values

Page 48: Intro to Mdx Aso

#Kscope

New ASO Model

Page 49: Intro to Mdx Aso

#Kscope

New ASO Model vs. Existing BSO

•4 GB ind files•22 GB pag files

26 GB application

•Full overnight refresh•3-4 Hours

•Intraday update•1 Hour•Cube is offline

during this window

•Only update current year

Processing Window

• 2 GB application• Processing Window– Full overnight • ~15 minutes– Full intraday • ~3-4 minutes– No down time

Page 50: Intro to Mdx Aso

#Kscope

What is MDX?

Page 51: Intro to Mdx Aso

#Kscope

MDX

Cons•Lacks formatting•Can be problematic on large data sets•Not well suited for general use by end users

Pros•Understands hierarchical relationships and member properties

•Can perform robust calculations utilizing many predefined functions

“Standardized” query language for OLAP

Multi-Dimensional Expression

Page 52: Intro to Mdx Aso

#Kscope

How do we use MDX with Essbase?

There are two primary ways, at

this time, to utilize MDX with

Essbase.

Query data from an Essbase database• Aggregate Storage

or Block Storage!

Construct member formulas• Aggregate Storage

only

Page 53: Intro to Mdx Aso

#Kscope

MDX Access

Users can execute MDX queries in variety of ways

MaxL

EAS console

Third Party tools

Page 54: Intro to Mdx Aso

#Kscope

MDX Basic Terms

● AXIS● SLICER● CUBE● SET● WITH● DIMENSION

● LAYER● MEMBER● TUPLE● FUNCTIONS● PROPERTIES

Page 55: Intro to Mdx Aso

#Kscope

MDX Basic Query

Proper Syntax

SELECT { [Year].Children } ON AXIS(0),{ [Product].Children } ON AXIS(1),{ [Market].Children } ON AXIS(2)FROM [Sample.Basic];WHERE ( [Measures].[Sales],[Scenario].[Actual] )

Page 56: Intro to Mdx Aso

#Kscope

MDX Basic Query

Where Slicer

AXIS(0)“Columns”

AXIS(1)“Rows”

AXIS(2)“Pages”

Page 57: Intro to Mdx Aso

#Kscope

SQLSELECT Product, Sales, MarginFROM dbo.TransactionsWHERE Year = ‘Jan’

MDXSELECT {[Measures].[Sales], [Measures].[Margin]} ON COLUMNS,{[Product].levels(0).members} ON ROWSFROM [SAMPASO].[BASIC]WHERE [Year].[Jan] Must Define axis

specification to render multi-dimensional in a report.

Page 58: Intro to Mdx Aso

#Kscope

Nesting rows using AXISSELECT {[Measures].[Sales], [Measures].[Margin]} ON AXIS(0),{[Product].levels(0).members} ON AXIS(1),{[Scenario].children} ON AXIS(2)FROM [SAMPASO].[BASIC]WHERE [Year].[Jan]

Nesting columns is a little differentSELECT {CrossJoin({[Measures].[Sales], [Measures].[Margin]},

{[Scenario].children})} ON axis(0),{[Product].levels(0).members} ON axis(1)FROM [SAMPASO].[BASIC]WHERE [Year].[Jan]

Page 59: Intro to Mdx Aso

#Kscope

● Naming Conventions● The most obvious way to identify a member is to start with the

name of the dimension and work downwards, specifying the members at each level in the hierarchy until we reach the required members - Fast Track to MDX, 2004, Whitehorn, Zare, Pasumansky

● [Jan]● [Year].[Jan]● [Year].[Qtr1].[Jan]

● * No difference in performance● * Particularly important with Duplicate Member names● * No quotes - “Jan” vs. [Jan]

Page 60: Intro to Mdx Aso

#Kscope

● Tuples● A tuple is defined as an intersection of exactly a single member from each

dimension in the cube. For each dimension that is not explicitly referenced, the current member is implicitly added to the tuple definition. A tuple always identifies (or has the potential to identify) a single cell in the multi-dimensional matrix. That could be an aggregate or a leaf level cell, but nevertheless one cell and only one cell is ever implied by a tuple. - Fast Track to MDX, 2004, Whitehorn, Zare, Pasumansky

● ([Year].[Jan], [Measures].[Sales], [Product].[Cola], [Market].[East])

● ([Year].[Jan], [Measures].[Sales])● ([Year].[Jan])

● * Wrap tuples in parenthesis ( )● * Similar to a cross-dimensional operator

● (“Jan”->”Sales”) vs. ([Year].[Jan], [Measures].[Sales])

Page 61: Intro to Mdx Aso

#Kscope

● Sets● A set is a collection of tuples with the same dimensionality. It

may have more than one tuple, but it can also have only one tuple, or even have zero tuples, in which case it is an empty set. - Fast Track to MDX, 2004, Whitehorn, Zare, Pasumansky

● {([Scenario].[Actual],[Measures].[Sales]), ([Scenario].[Actual],[Measures].[Margin])}

● {[Year].levels(0).members}● {[Measures].[Sales]}

● Wrap sets in { }

Page 62: Intro to Mdx Aso

#Kscope

We use MDX Expressions to define member formulas in the Essbase

outline

Same concept as member formulas in BSO

Many functions can be translated from Essbase calc language to MDX• In EAS go to Help -> Information Map ->

Technical Reference• Go to MDX -> Aggregate Storage Topics ->

MDX Outline Formulas• For version 7X go to MAXL -> MDX

Page 63: Intro to Mdx Aso

#Kscope

● @AVG● Calculator: @AVG(SKIPMISSING, @CHILDREN(East)); ● MDX: Avg([East].Children)

● For SKIPNONE - Avg([East].Children,IncludeEmpty)● @CHILDREN

● Calculator: @CHILDREN(Market);● MDX: Children([Market]) OR [Market].Children

● @ICHILDREN● Calculator: @ICHILDREN(Market);● MDX: Union({[Market]},{[Market].children})

● @CURRMBR● Calculator: @CURRMBR(Product);● MDX: CurrentMember([Product]) or [Product].CurrentMember

● @LEVMBRS● Calculator: @LEVMBRS(Product,0);● MDX: [Product].levels(0).Members

Page 64: Intro to Mdx Aso

#Kscope

● @LSIBLINGS● Calculator: @LSIBLINGS(Qtr4); ● MDX: MemberRange([Qtr4].FirstSibling, [Qtr4].Lag(1))

● @RSIBLINGS● Calculator: @RSIBLINGS(Qtr1);● MDX: MemberRange([Qtr1].Lead(1), [Qtr1].LastSibling)

● @PARENTVAL● Calculator: @PARENTVAL(Market, Sales);● MDX: ([Sales], [Market].CurrentMember.Parent).Value

● @REMOVE● Calculator: @REMOVE(@CHILDREN(East),@LIST(“New York”,Connecticut));● MDX: Except({[East].Children}, {[New York], [Connecticut]})

● @COUNT● Calculator: @COUNT(SKIPMISSING, @RANGE(Sales, Children(Product));● MDX:NonEmptyCount(CrossJoin({[Sales]},{[Product].Children}))

● For SKIPNONE – Count([Product].Children)

Page 65: Intro to Mdx Aso

#Kscope

● @IDESCENDANTS● Calculator: @IDESCENDANTS(Market);● MDX: Descendants([Market])

● @DESCENDANTS● Calculator: @DESCENDANTS(Market,0);● MDX: Descendants([Market], [Market].levels(0)) OR

● Leaves([Market]) –New in Sys 9● @ISICHILD

● Calculator: @ISICHILD(South);● MDX: IIF(Is([Market].CurrentMember,[South]) OR

IsChild([Market].CurrentMember,[South]), <True>,<False>)

Page 66: Intro to Mdx Aso

#Kscope

● Time Functionality● Leverage Analytic Dimensions

Page 67: Intro to Mdx Aso

#Kscope

● Period To Date Functions[QTD] = SUM( PeriodsToDate( [Year].Generations(2),

[Year].CurrentMember ), [View].[Per] )

[YTD] = SUM( PeriodsToDate( [Year].Generations(1), [Year].CurrentMember ), [View].[Per] )

Page 68: Intro to Mdx Aso

#Kscope

● Time Balancing

CASE WHEN IsUDA([Measures].CurrentMember, "TB_Last") THENIIF(IsLeaf([Year].CurrentMember), [View].[Per],

(ClosingPeriod ([Year].Levels(0), [Year].CurrentMember), [View].[Per])ELSE [View].[Per] END

Before

After

Page 69: Intro to Mdx Aso

#Kscope

● Formula Precedence (Solve Order)● The mechanism that standard MDX uses for dealing with dimensional

formula precedence is called solve order. Every calculated member has an associated solve order number, which is an integer that says what the calculation priority of the member is. When calculated members overlap on a cell, the member with the highest solve order number “wins” and is used to calculate the cell.

- MDX Solutions, 2006, Spofford, Harinath, Webb, Huang, Civardi

- Default value is 0, maximum value is 127- Multiple members can have the same solve order

- Dimension solve order sets the default solve order for all members in the dimension, you can still edit individual member’s order if required

- In addition to calculating the correct value, Solve Order can yield huge performance gains for calculated members

- Test, Test, Test!!!

Page 70: Intro to Mdx Aso

#Kscope

Recap

• MDX is a powerful query language, similar to SQL, that is used with multi-dimensional databases.

• MDX can be used to query both ASO and BSO Essbase cubes, although it is primarily used for member expressions in ASO models.

• Most Essbase calculator functions can be converted to MDX expressions – refer to the technical document.

• You can leverage MDX expression in ASO cubes to simulate Dynamic Time Series (Period To Date) and Time Balancing functionality.

• Solve Order is extremely important, both for calculating accurate results and performance.

Page 71: Intro to Mdx Aso

#Kscope

MDX as Administrator Tool

Provides a framework for administrators to analyze meta-data.

Easily generates member lists based on parameters to filter results

Apply complex logic to find answers to questions that can be used to troubleshoot or optimize an outline

Page 72: Intro to Mdx Aso

#Kscope

Set dml_output options

Page 73: Intro to Mdx Aso

#Kscope

Return All Members

alter session set dml_output alias off;set column_width 50;

SELECT {} ON AXIS(0),

[Year].Members ON AXIS(1)

FROM [Sample.Basic];

/*OR*/

SELECT {} ON AXIS(0),

Members([Year]) ON AXIS(1)

FROM [Sample.Basic];

Axis-1 +------------------------------------- (Year) (Qtr1) (Jan) (Feb) (Mar) (Qtr2) (Apr) (May) (Jun) (Qtr3) (Jul) (Aug) (Sep) (Qtr4) (Oct) (Nov) (Dec)

Page 74: Intro to Mdx Aso

#Kscope

Return All Children

SELECT {} ON AXIS(0),

{[Year].[Qtr1].Children} ON AXIS(1)

FROM [Sample.Basic];

/*OR*/

SELECT {} ON AXIS(0),

{[Qtr1].Children} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+--------------- (Jan)

(Feb)

(Mar)

Page 75: Intro to Mdx Aso

#Kscope

Combining two sets

SELECT {} ON AXIS(0),

{[Qtr1].Children, [Qtr2].Children} ON AXIS(1)

FROM [Sample.Basic];

/*Beware of Duplicates*/

SELECT {} ON AXIS(0),

{[Year].Members, [Year].Children} ON AXIS(1)

FROM [Sample.Basic];

Axis-1 +--------------------------------------- (Jan) (Feb) (Mar) (Apr) (May) (Jun)

Axis-1 +------------------------------------------------- (Year) (Qtr1) (Jan) (Feb) (Mar) (Qtr2) (Apr) (May) (Jun) (Qtr3) (Jul) (Aug) (Sep) (Qtr4) (Oct) (Nov) (Dec) (Qtr1) (Qtr2) (Qtr3) (Qtr4)

Page 76: Intro to Mdx Aso

#Kscope

Combining two sets

/*Removes Duplicates*/

SELECT {} ON AXIS(0),

Distinct({[Year].Members, [Year].Children}) ON AXIS(1)

FROM [Sample.Basic];

/*OR*/

SELECT {} ON AXIS(0),

Union({[Year].Members}, {[Year].Children}) ON AXIS(1)

FROM [Sample.Basic];

/* ALL keyword will keep duplicates*/

SELECT {} ON AXIS(0),

Union({[Year].Members}, {[Year].Children}, ALL) ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+---------- (Year)

(Qtr1)

(Jan)

(Feb)

(Mar)

(Qtr2)

(Apr)

(May)

(Jun)

(Qtr3)

(Jul)

(Aug)

(Sep)

(Qtr4)

(Oct)

(Nov)

(Dec)

Axis-1

+------- (Year)

(Qtr1)

(Jan)

(Feb)

(Mar)

(Qtr2)

(Apr)

(May)

(Jun)

(Qtr3)

(Jul)

(Aug)

(Sep)

(Qtr4)

(Oct)

(Nov)

(Dec)

(Qtr1)

(Qtr2)

(Qtr3)

(Qtr4)

Page 77: Intro to Mdx Aso

#Kscope

Descendants including member

/*Descendants, including member*/

SELECT {} ON AXIS(0),

{Descendants([Year])} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+---------------------------------------

(Year)

(Qtr1)

(Jan)

(Feb)

(Mar)

(Qtr2)

(Apr)

(May)

(Jun)

(Qtr3)

(Jul)

(Aug)

(Sep)

(Qtr4)

(Oct)

(Nov)

(Dec)

Page 78: Intro to Mdx Aso

#Kscope

Descendants excluding member

/*Descendants, excluding member*/

SELECT {} ON AXIS(0),

Except({Descendants([Year])}, {[Year]}) ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+---------------------------------------

(Qtr1)

(Jan)

(Feb)

(Mar)

(Qtr2)

(Apr)

(May)

(Jun)

(Qtr3)

(Jul)

(Aug)

(Sep)

(Qtr4)

(Oct)

(Nov)

(Dec)

Page 79: Intro to Mdx Aso

#Kscope

Descendants of a member mid-dimension

/*Descendants of a member mid-dimension*/

SELECT {} ON AXIS(0),

{Descendants([Qtr1])} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+---------- (Qtr1)

(Jan)

(Feb)

(Mar)

Page 80: Intro to Mdx Aso

#Kscope

Descendants – Level 1 only

/*Only level 1 descendants*/

SELECT {} ON AXIS(0),

{Descendants([Year], 1)} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+----------- (Qtr1)

(Qtr2)

(Qtr3)

(Qtr4)

Page 81: Intro to Mdx Aso

#Kscope

Descendants – Level 0 only

/*Only level 0 descendants*/

SELECT {} ON AXIS(0),

{Descendants([Year], Levels([Year],0))} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+------- (Jan)

(Feb)

(Mar)

(Apr)

(May)

(Jun)

(Jul)

(Aug)

(Sep)

(Oct)

(Nov)

(Dec)

Page 82: Intro to Mdx Aso

#Kscope

Ancestors - up two levels

/*Ancestors, up 2 levels*/

SELECT {} ON AXIS(0),

{Ancestors([Jan], 2)} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+-------- (Year)

(Qtr1)

(Jan)

Page 83: Intro to Mdx Aso

#Kscope

Ancestors - up one level

/*Ancestors, up 1 level*/

SELECT {} ON AXIS(0),

{Ancestors([Jan], 1)} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+------- (Qtr1)

(Jan)

Page 84: Intro to Mdx Aso

#Kscope

Ancestors - up zero levels

/*Ancestors up 0 levels*//*Only returns the member, but it is

valid*/

SELECT {} ON AXIS(0),

{Ancestors([Jan], 0)} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+-------- (Jan)

Page 85: Intro to Mdx Aso

#Kscope

Ancestors - up 100 levels

/*Ancestors up 100 levels*//*Doesn't matter that there are Less than 100 levels, still valid*/

SELECT {} ON AXIS(0),

{Ancestors([Jan], 100)} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+-------- (Year)

(Qtr1)

(Jan)

Page 86: Intro to Mdx Aso

#Kscope

Cousins

/*Returns a child member at the same position as a member from another ancestor*/

SELECT {} ON AXIS(0),

{Cousin([Qtr1].[Feb], [Qtr2])} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+---------- (May)

Page 87: Intro to Mdx Aso

#Kscope

Level 0 members

/*all level 0 members of dimension*/

SELECT {} ON AXIS(0),

{[Year].levels(0).members} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+------- (Jan)

(Feb)

(Mar)

(Apr)

(May)

(Jun)

(Jul)

(Aug)

(Sep)

(Oct)

(Nov)

(Dec)

Page 88: Intro to Mdx Aso

#Kscope

Level 0 descendants of a member

/*level 0 descendants of a member*/

SELECT {} ON AXIS(0),

{Descendants([Time].[1st Half], [Time].levels(0), SELF)} ON AXIS(1)

FROM [ASOSamp.Sample];

/*OR*/

SELECT {} ON AXIS(0),

{Descendants([Time].[1st Half], 100, LEAVES)} ON AXIS(1)

FROM [ASOSamp.Sample];

Axis-1

+------ (Jan)

(Feb)

(Mar)

(Apr)

(May)

(Jun)

Page 89: Intro to Mdx Aso

#Kscope

What Level ?

/*list of all members with levels*/

SELECT {} ON AXIS(0),[Time].members DIMENSION PROPERTIES [Time].[LEVEL_NUMBER] ON AXIS(1)FROM [ASOsamp.Sample];

Axis-1 Axis-1.properties +-------------------------------------------------+------------------------------------------------- (Time) (LEVEL_NUMBER = 4, type: ULONG, ) (MTD) (LEVEL_NUMBER = 3, type: ULONG, ) (1st Half) (LEVEL_NUMBER = 2, type: ULONG, ) (Qtr1) (LEVEL_NUMBER = 1, type: ULONG, ) (Jan) (LEVEL_NUMBER = 0, type: ULONG, ) (Feb) (LEVEL_NUMBER = 0, type: ULONG, ) (Mar) (LEVEL_NUMBER = 0, type: ULONG, ) (Qtr2) (LEVEL_NUMBER = 1, type: ULONG, ) (Apr) (LEVEL_NUMBER = 0, type: ULONG, ) (May) (LEVEL_NUMBER = 0, type: ULONG, ) (Jun) (LEVEL_NUMBER = 0, type: ULONG, ) (2nd Half) (LEVEL_NUMBER = 2, type: ULONG, ) (Qtr3) (LEVEL_NUMBER = 1, type: ULONG, ) (Jul) (LEVEL_NUMBER = 0, type: ULONG, ) (Aug) (LEVEL_NUMBER = 0, type: ULONG, ) (Sep) (LEVEL_NUMBER = 0, type: ULONG, ) (Qtr4) (LEVEL_NUMBER = 1, type: ULONG, ) (Oct) (LEVEL_NUMBER = 0, type: ULONG, ) (Nov) (LEVEL_NUMBER = 0, type: ULONG, ) (Dec) (LEVEL_NUMBER = 0, type: ULONG, )

Page 90: Intro to Mdx Aso

#Kscope

What Level ?

/*Specific member with level*/

SELECT {} ON AXIS(0),{[Qtr1]} DIMENSION PROPERTIES [Time].[LEVEL_NUMBER] ON AXIS(1)FROM [ASOsamp.Sample];

Axis-1 Axis-1.properties +-------------------------------------------------+------------------------------------------------- (Qtr1) (LEVEL_NUMBER = 1, type: ULONG, )

Page 91: Intro to Mdx Aso

#Kscope

Members on same level

/*Return Members on same level*/

SELECT {} ON AXIS(0),

{[Time].[Qtr1].Level.members} ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+---------- (Qtr1)

(Qtr2)

(Qtr3)

(Qtr4)

Page 92: Intro to Mdx Aso

#Kscope

What Generation ?

/*list of all members with Generation*/

SELECT {} ON AXIS(0),[Time].members DIMENSION PROPERTIES [Time].[GEN_NUMBER] ON AXIS(1)FROM [ASOsamp.Sample];

Axis-1 Axis-1.properties +-------------------------------------------------+------------------------------------------------- (Time) (GEN_NUMBER = 1, type: ULONG, ) (MTD) (GEN_NUMBER = 2, type: ULONG, ) (1st Half) (GEN_NUMBER = 3, type: ULONG, ) (Qtr1) (GEN_NUMBER = 4, type: ULONG, ) (Jan) (GEN_NUMBER = 5, type: ULONG, ) (Feb) (GEN_NUMBER = 5, type: ULONG, ) (Mar) (GEN_NUMBER = 5, type: ULONG, ) (Qtr2) (GEN_NUMBER = 4, type: ULONG, ) (Apr) (GEN_NUMBER = 5, type: ULONG, ) (May) (GEN_NUMBER = 5, type: ULONG, ) (Jun) (GEN_NUMBER = 5, type: ULONG, ) (2nd Half) (GEN_NUMBER = 3, type: ULONG, ) (Qtr3) (GEN_NUMBER = 4, type: ULONG, ) (Jul) (GEN_NUMBER = 5, type: ULONG, ) (Aug) (GEN_NUMBER = 5, type: ULONG, ) (Sep) (GEN_NUMBER = 5, type: ULONG, ) (Qtr4) (GEN_NUMBER = 4, type: ULONG, ) (Oct) (GEN_NUMBER = 5, type: ULONG, ) (Nov) (GEN_NUMBER = 5, type: ULONG, ) (Dec) (GEN_NUMBER = 5, type: ULONG, )

Page 93: Intro to Mdx Aso

#Kscope

What Generation ?

/*Specific member with Generation*/

SELECT {} ON AXIS(0),{[Qtr1]} DIMENSION PROPERTIES [Time].[GEN_NUMBER] ON AXIS(1)FROM [ASOsamp.Sample];

Axis-1 Axis-1.properties +-------------------------------------------------+------------------------------------------------- (Qtr1) (GEN_NUMBER = 4, type: ULONG, )

Page 94: Intro to Mdx Aso

#Kscope

Members on same generation

/*Return Members on same Generation*/

SELECT {} ON AXIS(0),

{[Time].[Qtr1].Generation.members} ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+--------- (Qtr1)

(Qtr2)

(Qtr3)

(Qtr4)

Page 95: Intro to Mdx Aso

#Kscope

Counts

/*Count level 0 member*/

WITHMEMBER

[Year].[YearMemberCount] AS 'Count([Year].Levels(0).members)'

SELECT {[Measures]} ON AXIS(0),

{[Year].[YearMemberCount]} on AXIS(1)

FROM Sample.Basic;

Axis-1 (Measures) +-------------------------------------------------+------------------------------------------------- (YearMemberCount) 12

Page 96: Intro to Mdx Aso

#Kscope

Count children

/*Count children*/

WITHMEMBER

[Year].[YearChildrenCount] AS 'Count([Year].Children)'

SELECT {[Measures]} ON AXIS(0),

{[Year].[YearChildrenCount]} on AXIS(1)

FROM Sample.Basic;

Axis-1 (Measures) +-------------------------------------------------+------------------------------------------------- (YearChildrenCount) 4

Page 97: Intro to Mdx Aso

#Kscope

Count descendants

/*Count descendants*/

WITHMEMBER

[Year].[YearDescCount] AS 'Count(Descendants([Year]))'

SELECT {[Measures]} ON AXIS(0),

{[Year].[YearDescCount]} on AXIS(1)

FROM Sample.Basic;

Axis-1 (Measures) +-------------------------------------------------+------------------------------------------------- (YearDescCount) 17

Page 98: Intro to Mdx Aso

#Kscope

Using Counts with filters

/*Members with one child*/ SELECT {} ON AXIS(0),

{FILTER({[Stores].members},COUNT({[Stores].CurrentMember.Children}, IncludeEmpty) = 1)} ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+---------- (Electronic Essentials)

(Club Electronics)

Page 99: Intro to Mdx Aso

#Kscope

Using Counts with filters

/*Members with more than 100 children*/

SELECT {} ON AXIS(0),

{FILTER({[Geography].members},COUNT({[Geography].CurrentMember.Children}, IncludeEmpty) > 100)} ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+--------- (CO)

(KS)

(NE)

(IA)

(IL)

(IN)

(MI)

(MN)

(MO)

(OH)

(WI)

(MA)

(ME)

(NJ)

(NY)

(PA)

(AL)

(AR)

(FL)

(GA)

(KY)

(LA)

(MD)

(MS)

(NC)

(SC)

(TN)

(VA)

(WV)

(OK)

(TX)

(CA)

(OR)

(WA)

Page 100: Intro to Mdx Aso

#Kscope

Criteria based member search

/*Stores starting with "801"*/ SELECT {} ON AXIS(0),

{FILTER({[Geography].members},Substring([Geography].CurrentMember.Member_Name, 1, 3) = "801")} ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+----------- (80101)

(80107)

(80154)

(80116)

(80126)

(80117)

(80118)

(80124)

(80160)

(80161)

(80163)

(80165)

(80135)

Page 101: Intro to Mdx Aso

#Kscope

Criteria based member search

/*Area Codes ending with "25"*/ SELECT {} ON AXIS(0),

{FILTER({[Area Code].levels(0).members},Substring([Area Code].CurrentMember.Member_Name,

Len([Area Code].CurrentMember.Member_Name ) - 1) = "25")} ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+-------- (225)

(425)

(925)

Page 102: Intro to Mdx Aso

#Kscope

Criteria based member search

/*Products with word "Digital"*/

SELECT {} ON AXIS(0),

{FILTER({[Products].members},InStr(1, [Products].CurrentMember.Member_Name,

"Digital", 1) > 0)} ON AXIS(1)

FROM [ASOsamp.Sample];

/*Distinct Products with word "Digital", doesn't work, Shared members are not duplicates!*/

SELECT {} ON AXIS(0),

Distinct({FILTER({[Products].members},InStr(1, [Products].CurrentMember.Member_Name,

"Digital", 1) > 0)}) ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+--------------------------- (Digital Cameras/Camcorders)

(Digital Cameras)

(Digital Recorders)

(Digital Recorders)

Page 103: Intro to Mdx Aso

#Kscope

Using Distinct

/*An example where Distinct works*/

SELECT {} ON AXIS(0),

{[Time].levels(0).members, [Qtr1].Children} ON AXIS(1)

FROM [ASOsamp.Sample];

/*vs*/

SELECT {} ON AXIS(0),

Distinct({[Time].levels(0).members, [Qtr1].Children}) ON AXIS(1)

FROM [ASOsamp.Sample];

Axis-1

+---------- (Jan)

(Feb)

(Mar)

(Apr)

(May)

(Jun)

(Jul)

(Aug)

(Sep)

(Oct)

(Nov)

(Dec)

(Jan)

(Feb)

(Mar)

Axis-1

+---------- (Jan)

(Feb)

(Mar)

(Apr)

(May)

(Jun)

(Jul)

(Aug)

(Sep)

(Oct)

(Nov)

(Dec)

Page 104: Intro to Mdx Aso

#Kscope

Member Properties

/* 0 = Member (Non-Measure) 1 = Dimension Root member 2 = Member with Formula 3 = Measure */

SELECT {} ON AXIS(0),

[Measures].levels(0).members DIMENSION PROPERTIES MEMBER_TYPE ON AXIS(1) FROM ASOsamp.Sample;

Axis-1 Axis-1.properties +-------------------------------------------------+------------------------------------------------- (Original Price) (MEMBER_TYPE = 3, type: ULONG, ) (Price Paid) (MEMBER_TYPE = 3, type: ULONG, ) (Returns) (MEMBER_TYPE = 3, type: ULONG, ) (Units) (MEMBER_TYPE = 3, type: ULONG, ) (Transactions) (MEMBER_TYPE = 3, type: ULONG, ) (Avg Units/Transaction) (MEMBER_TYPE = 2, type: ULONG, ) (% of Total) (MEMBER_TYPE = 2, type: ULONG, ) (Test) (MEMBER_TYPE = 2, type: ULONG, )

Page 105: Intro to Mdx Aso

#Kscope

Filter member properties

/*Filter by Members with formulas*/

SELECT {} ON AXIS(0),

{FILTER([Measures].levels(0).members, [Measures].CurrentMember.MEMBER_TYPE = 2)} ON AXIS(1) FROM ASOsamp.Sample;

Axis-1

+---------------------- (Avg Units/Transaction)

(% of Total)

(Test)

Page 106: Intro to Mdx Aso

#Kscope

Member Properties

/*Expense Members*/

SELECT {} ON AXIS(0),

[Measures].members DIMENSION PROPERTIES [Measures].[IS_EXPENSE] ON AXIS(1) FROM Sample.Basic; Axis-1 Axis-1.properties +-------------------------------------------------+------------------------------------------------- (Measures) (IS_EXPENSE = FALSE, type: BOOL, ) (Profit) (IS_EXPENSE = FALSE, type: BOOL, ) (Margin) (IS_EXPENSE = FALSE, type: BOOL, ) (Sales) (IS_EXPENSE = FALSE, type: BOOL, ) (COGS) (IS_EXPENSE = TRUE, type: BOOL, ) (Total Expenses) (IS_EXPENSE = TRUE, type: BOOL, ) (Marketing) (IS_EXPENSE = TRUE, type: BOOL, ) (Payroll) (IS_EXPENSE = TRUE, type: BOOL, ) (Misc) (IS_EXPENSE = TRUE, type: BOOL, ) (Inventory) (IS_EXPENSE = FALSE, type: BOOL, ) (Opening Inventory) (IS_EXPENSE = TRUE, type: BOOL, ) (Additions) (IS_EXPENSE = TRUE, type: BOOL, ) (Ending Inventory) (IS_EXPENSE = TRUE, type: BOOL, ) (Ratios) (IS_EXPENSE = FALSE, type: BOOL, ) (Margin %) (IS_EXPENSE = FALSE, type: BOOL, ) (Profit %) (IS_EXPENSE = FALSE, type: BOOL, ) (Profit per Ounce) (IS_EXPENSE = FALSE, type: BOOL, ) (Test) (IS_EXPENSE = FALSE, type: BOOL, ) (var) (IS_EXPENSE = FALSE, type: BOOL, ) (Flag) (IS_EXPENSE = FALSE, type: BOOL, ) (Test2) (IS_EXPENSE = FALSE, type: BOOL, )

Page 107: Intro to Mdx Aso

#Kscope

Filter member properties

/*Expense members*/

SELECT {} ON AXIS(0),

{FILTER([Measures].members, IsAccType([Measures].CurrentMember, Expense))}

ON AXIS(1) FROM Sample.Basic;

Axis-1

+----------------- (COGS)

(Total Expenses)

(Marketing)

(Payroll)

(Misc)

(Opening Inventory)

(Additions)

(Ending Inventory)

Page 108: Intro to Mdx Aso

#Kscope

Filter Text Attributes

/* Text Attribute */

SELECT {} ON AXIS(0),

Attribute([Bottle]) ON AXIS(1)

FROM [Sample.Basic];

/* OR */

SELECT {} ON AXIS(0),

Withattr([Pkg Type], "==", "Can") ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+------------ (100-30)

(200-10)

(200-20)

(200-30)

(200-40)

(300-10)

(300-20)

(400-10)

(400-20)

(400-30)

Axis-1

+------------ (100-10)

(100-20)

(300-30)

Page 109: Intro to Mdx Aso

#Kscope

Filter Boolean Attributes

/* Boolean Attribute */ SELECT {} ON AXIS(0),

{FILTER({[Product].members},[Product].CurrentMember.[Caffeinated])} ON AXIS(1)

FROM [Sample.Basic];

/*OR*/

SELECT {} ON AXIS(0),

Withattr([Caffeinated], "==", "TRUE") ON AXIS(1)

FROM [Sample.Basic];

/*Opposite*/

SELECT {} ON AXIS(0),

Withattr([Caffeinated], "==", "FALSE") ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+----------- (100-10)

(100-20)

(200-10)

(200-20)

(300-10)

(300-20)

(300-30)

Axis-1

+-----------(100-30)

(200-30)

(200-40)

(400-10)

(400-20)

(400-30)

Page 110: Intro to Mdx Aso

#Kscope

Filter Boolean Attributes

/* this won't work */

SELECT {} ON AXIS(0),

Attribute([True]) ON AXIS(1)

FROM [Sample.Basic];

/*OR*/

SELECT {} ON AXIS(0),

Attribute([Caffeinated].[True]) ON AXIS(1)

FROM [Sample.Basic];

ERROR - 1260046 - Unknown Member True used in query.

Page 111: Intro to Mdx Aso

#Kscope

Filter Date Attributes

/* Date attribute */

/*This won't work*/

SELECT {} ON AXIS(0),

Withattr([Intro Date], "==", "04-01-1996") ON AXIS(1)

FROM [Sample.Basic];

/*This is correct*/

SELECT {} ON AXIS(0),

Withattr([Intro Date], "==", Todate("mm-dd-yyyy", "04-01-1996")) ON AXIS(1)

FROM [Sample.Basic];

ERROR - 1001078 - Cannot form a valid attribute value from [04-01-1996].

Axis-1

+---------------------------------- (100-20)

(100-30)

Page 112: Intro to Mdx Aso

#Kscope

Filter Numeric Attributes

/* Numeric Attribute */

SELECT {} ON AXIS(0),

Withattr([Population], ">=", 12000000) ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+-------------- (New York)

(Florida)

(California)

(Texas)

(Illinois)

(Ohio)

Page 113: Intro to Mdx Aso

#Kscope

Filter UDA

SELECT {} ON AXIS(0),

{Uda([Market], "Major Market")} ON AXIS(1)

FROM [Sample.Basic];

/*OR*/

SELECT {} ON AXIS(0),

{FILTER({[Market].members},IsUda([Market].CurrentMember, "Major Market"))} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+--------------- (East)

(New York)

(Massachusetts)

(Florida)

(California)

(Texas)

(Central)

(Illinois)

(Ohio)

(Colorado)

Page 114: Intro to Mdx Aso

#Kscope

Filter UDA

/*Combine Functions to further define filter*/

SELECT {} ON AXIS(0),

{FILTER({Uda([Market], "Major Market")},Substring([Market].CurrentMember.Member_Name, 1, 3) = "New")} ON AXIS(1)

FROM [Sample.Basic];

Axis-1

+------------ (New York)

Page 115: Intro to Mdx Aso

#Kscope

Count UDA

/* count members with a UDA */

WITHMEMBER

[Market].[MajorMarketCount] AS 'Count(UDA([Market], "Major Market"))‘

SELECT {[Measures]} ON AXIS(0),{[Market].[MajorMarketCount]} on AXIS(1)

FROM Sample.Basic;

Axis-1 (Measures) +-------------------------------------------------+------------------------------------------------- (MajorMarketCount) 10

Page 116: Intro to Mdx Aso

#Kscope

Count Attribute

/* Count members with specific attribute */

WITHMEMBER

[Geography].[AreaCode719Count] AS 'Count(Withattr([Area Code], "==", "719"))‘

SELECT {[Measures]} ON AXIS(0),{[Geography].[AreaCode719Count]} on AXIS(1)

FROM ASOSamp.Sample;

Axis-1 (Measures) +-------------------------------------------------+------------------------------------------------- (AreaCode719Count) 50

Page 117: Intro to Mdx Aso

#Kscope

Count Attribute

/* Count mebers with attribute and members without attribute */

WITHMEMBER

[Geography].[NoAttribute] AS 'Count(Filter( [Geography].levels(0).members, NOT

IsValid([Geography].CurrentMember.[Area Code])))‘MEMBER

[Geography].[HasAttribute] AS 'Count(Filter( [Geography].levels(0).members, IsValid([Geography].CurrentMember.

[Area Code])))‘MEMBER

[Geography].[Lev0Count] AS'Count([Geography].Levels(0).members)‘

SELECT {[Measures]} ON AXIS(0),{[Geography].[NoAttribute], [Geography].[HasAttribute], [Geography].[Lev0Count]} on AXIS(1)

FROM ASOSamp.Sample;

Axis-1 (Measures) +-------------------------------------------------+------------------------------------------------- (NoAttribute) 1 (HasAttribute) 9397 (Lev0Count) 9398

Page 118: Intro to Mdx Aso

#Kscope

Filter members missing attribute

SELECT {} ON AXIS(0),

{Filter( [Geography].levels(0).members, NOT IsValid([Geography].CurrentMember.[Area Code]))} on AXIS(1)

FROM ASOSamp.Sample;

Axis-1

+--------- (80101)

Page 119: Intro to Mdx Aso

#Kscope

Finding Shared or Duplicate Members

WITH MEMBER [Measures].[Products_SharedMembers] AS'Count(Generate({[Products].CurrentMember} AS [var1],Generate(Filter([Products].Levels(0).Members,[Products].CurrentMember.[MEMBER_NAME] = [var1].Item(0).Item(0).[MEMBER_NAME]),Filter ({[Products].CurrentMember},IsAncestor( [Products], [Products].CurrentMember )))))'

SELECT{[Measures].[Products_SharedMembers]} ON AXIS(0), [Products].Levels(0).Members ON AXIS(1)FROM [ASOSamp.Sample];

(Digital Cameras) 1

(Camcorders) 1

(Photo Printers) 1

(Handhelds) 1

(Memory) 1

(Other Accessories) 1

(Boomboxes) 1

(Radios) 1

(Direct View) 1

(Projection TVs) 1

(Flat Panel) 2

(HDTV) 2

(Stands) 1

(Home Theater) 1

(HiFi Systems) 1

(Digital Recorders) 2

(DVD) 1

(Desktops) 1

(Notebooks) 2

(Displays) 1

(CD/DVD drives) 1

(Flat Panel) 2

(HDTV) 2

(Digital Recorders) 2

(Notebooks) 2*Code adapted from an example given by George Spofford

Page 120: Intro to Mdx Aso

#Kscope

Finding Shared or Duplicate Members

WITH MEMBER [Measures].[Products_SharedMembers] AS

'Count(Generate({[Products].CurrentMember} AS [var1],Generate(Filter([Products].Levels(0).Members,[Products].CurrentMember.[MEMBER_NAME] = [var1].Item(0).Item(0).[MEMBER_NAME]),Filter({[Products].CurrentMember},IsAncestor([Products], [Products].CurrentMember)))))'

SELECT{} ON AXIS(0), Filter(Except([Products].Levels(0).Members, Descendants([All Merchandise])), [Measures].[Products_SharedMembers] > 1) ON AXIS(1)FROM [ASOSamp.Sample];

Axis-1

+-------------(Flat Panel)

(HDTV)

(Digital Recorders)

(Notebooks)

*Code adapted from an example given by George Spofford

Page 121: Intro to Mdx Aso

#Kscope

Sparse Optimization using MDX

Conventional wisdom has been to order outline from smallest sparse dimension to largest sparse dimension.

Edward Roske has said● “The smallest to largest sparse is a total misnomer. 

What you actually want to do is make sure the number of blocks grows as slowly as possible (so make them in order of lowest ratio of parents:children)”

Page 122: Intro to Mdx Aso

#Kscope

Sparse Optimization using MDX

Using Sample.Basic as an example● Market dimension has 25 stored members● Product dimension has 18 stored members

Conventional wisdom says that the Product Dimension would come before the Market dimension in outline order in order to adhere to the “hour glass”.

Page 123: Intro to Mdx Aso

#Kscope

Sparse Optimization using MDX

To keep things simple, let’s assume that all members are stored and there is one primary hierarchy ● (I’ve removed the Diet alternate rollup)

If we use the logic that● All members are parent, except for level 0 members

AND● All members are Children, except for the dimension root

member Then we can construct an MDX query to calculate

the parent to child ratio

Page 124: Intro to Mdx Aso

#Kscope

Sparse Optimization using MDX

WITH MEMBER [Measures].[Market Ratio] AS '(COUNT([Market].members) - COUNT([Market].levels(0).members)) /

(COUNT([Market].members) - 1)'

MEMBER [Measures].[Product Ratio] AS'(COUNT(Except([Product].members, Descendants([Diet]))) -

COUNT(Except([Product].levels(0).members, Descendants([Diet])))) / (COUNT(Except([Product].members, Descendants([Diet]))) - 1)'

SELECT {[Year]} ON AXIS(0),{ [Measures].[Market Ratio], [Measures].[Product Ratio] } ON

AXIS(1)FROM [Sample.Basic];Axis-1----------------------------------------------------------(Market Ratio) 0.208333333333333(Product Ratio) 0.294117647058824

Page 125: Intro to Mdx Aso

#Kscope

Sparse Optimization using MDX

Market Dimension has more stored members than Product● 25 vs. 18

However the Parent:Child ratio of Market is smaller than the Parent:Child ratio of Product● .21 vs. .29

In order to optimize calc time, in theory, Market should come before Product in the outline

You’re mileage may vary!

Page 126: Intro to Mdx Aso

#Kscope

Questions

There are three types of answers

GoodFast

Cheap

You can choose two!