Olap and Mdx - Day 1

download Olap and Mdx - Day 1

of 41

description

Olap and MDX

Transcript of Olap and Mdx - Day 1

  • MSAS MDXPresenter NameTitle

  • MDX Syntax

  • MDX Syntax

  • Specifying a MeasureIf you wish to define rows and columns that are not measures themselves then a measure can be selected via the WHERE clause to specify context.SELECT {[Time].[1997],[Time].[1998]} on rows, {[Store].[All Stores].[USA]} on columnsFROM WarehouseWHERE [Measures].[Warehouse Sales]

  • MDX SyntaxThe SELECT clause defines the contents of the axes.The FROM clause defines the connection to the cube or OLAP source.The WHERE clause defines the slicer or context based on members and member sets.

    MDX results are a smaller multi-dimensional cube derived from the original cube source. SQL results are columnar and only ever define a single axis.

  • WITH MEMBERWITH MEMBER can be used to create calculated members.Example: WITH MEMBER dimension.name AS 'Expression' dimension is the target dimension to contain the new calculated member.name is the alias for the result of the new expressionExpression is the calculation that is required to define the new calculated member.

  • WITH MEMBERWITH MEMBER [Measures].[Margin] AS '[Measures].[Warehouse Sales]-[Measures].[Warehouse Cost]'SELECT {([Time].[1998].children)} ON COLUMNS, {([Warehouse].[Country].members)} ON ROWSFROM WarehouseWHERE ([Measures].[Margin])

  • Commenting MDXComments can written in MSAS MDX using//--/* */// and -- can be placed on lines of existing code. The rest of the line will be interperted as a comment. This applies to a single line only./* */ (ellipsis replaces comment text) can be used within existing code. Any text between /* and */ will be treated as a comment. This can be used across multiple lines of code.

  • Set Syntax{ } defines a set of members

    Example: {[Time].[1997],[Time].[1998]}

    The set of two members (1997 and 1998) from the Time Dimension.The result is really a set of tuples where each tuple is defined by the intersection of the listed members and the default measure for the cube.

  • OLAP Cubes - Whats a tuple?Tuple is a combination of members from one or more dimensions. In this case we have:tuple([Q4], [Golf], [WA])All other dimension members are implied.The value returned would be the default measure i.e. [unit sales]

  • C8 Report Studio Speak- Its still a tupletuple( currentMember([goc].[Products].[Products] ), [Quantity sold] , [2006 Q 4] )= 1,222

  • Defining a TupleParentheses are used to define a tupleSELECT {[Time].[1997],[Time].[1998]} on rows, {[Store].[All Stores].[USA]} on columnsFROM WarehouseWHERE ([Measures].[Warehouse Sales],[Store Type].[All Store Type].[Deluxe Supermarket])

  • Tuples on edgesA tuple defined for an axis (edge) will result in nested membersSELECT {[Product].[All Products].[Drink].[Alcoholic Beverages]} on rows, {([Store].[All Stores].[USA],[Time].[1997])} on columnsFROM WarehouseWHERE ([Measures].[Warehouse Sales])

  • Specifying RangesThe : can be used to leverage the natural order of members within a levelSELECT { [Measures].[Store Invoice]: [Measures].[Warehouse Profit]} ON COLUMNS, { [Time].[1997], [Time].[1998] } ON ROWSFROM WarehouseWHERE([Warehouse].[All Warehouses].[USA].[CA])

  • NON EMPTYThe NON EMPTY clause can be used to eliminate tuples that do not have defined measure values.SELECT { [Measures].[Units Shipped], [Measures].[Units Ordered] } ON COLUMNS, [Store].Members ON ROWSFROM [Warehouse]

  • NON EMPTYThe NON EMPTY clause can be used to eliminate tuples that do not have defined measure values.SELECT { [Measures].[Units Shipped], [Measures].[Units Ordered] } ON COLUMNS, NON EMPTY [Store].Members ON ROWSFROM [Warehouse]

  • Methods and FunctionsMSAS mixes two forms, Method and Function calls.Methods[Time].[Year].membersSELECT { [Time].[Year].members } ON ROWS, {[Measures].[Warehouse Cost]} on COLUMNSFROM WarehouseFunctionsAncestor( [Time].[1997].[Q1], [Time].[Year] )SELECT {Ancestor( [Time].[1997].[Q1], [Time].[Year] )} ON ROWS, {[Measures].[Warehouse Cost]} on COLUMNSFROM Warehouse

  • Methods.Parent .Children .FirstChild .LastChild .FirstSibling .LastSibling .Members.CurrentMember.PrevMember.NextMember.Item()

    (Others exist)

  • Dimensions, MDX & The Family Tree- Navigating a dimension using MDXJanFebMarQ1Q2Q3OctNovDecQ42005Q1Q2Q3Q42006All

  • Sets of data in MDX- Collecting data to use as a group using MDXJanFebMarQ1Q2Q3OctNovDecQ42005Q1Q2Q3Q42006All

  • ParentReturns the member directly above the specified member in the same hierarchySELECT {[Time].[Year].members} ON COLUMNS, {[Booker].Parent} ON ROWSFROM [Warehouse]WHERE ([Measures].[Units Shipped])

  • .ChildrenThe members directly below the specified member of the hierarchySELECT {[Store].[All Stores].[Canada]} ON COLUMNS, {[Time].[Year].[1998].children} ON ROWSFROM [Warehouse]WHERE ([Measures].[Units Shipped])

  • Workshop.Parent Which city is [Bellmont Distributing] in?What is the parent of [Dairy]?.Children What types of Drinks are sold?.FirstChild What is the first month available in the Time dimension?.LastChild What is the last month available in the Time dimension?.FirstSibling What is the first State/Province relative to [Warehouse].[Veracruz] from the same country?.LastSibling What is the last State/Province relative to [Warehouse].[Veracruz] from the same country?.Members Make a list of all the Store Cities. Make a list of all Years, Quarters, and Months..NextMember Which year follows 1997?.PrevMember What is the previous measure from [Store Invoice]?

  • CurrentMemberAllows processing of an expression relative to the current position within the members on an axis (dimension)WITH MEMBER [Measures].[Percent of Base] AS '([Warehouse].currentMember,[Measures].[Warehouse Sales])/([Warehouse].[All Warehouses],[Measures].[Warehouse Sales])'SELECT {([Time].[1998])} ON COLUMNS, {([Warehouse].[Country].members)} ON ROWSFROM WarehouseWHERE ([Measures].[Percent of Base])

  • CurrentMember WorkshopCalculate the Year over Year variance in Warehouse Sales for each Country. i.e. difference of the current Year from the prior Year.WITH MEMBER [Measures].[YOY Variance] AS Expression'SELECT {([Time].[Year].members)} ON COLUMNS, {([Warehouse].[Country].members)} ON ROWSFROM WarehouseWHERE ([Measures].[YOY Variance])

  • Item (tuple version)Tuple.Item(Numeric Expression)Returns the member at the zero-based index defined by Numeric Expression.SELECT {[Warehouse].[All Warehouses].[Canada]} on ROWS, {([Time].[1998],[Store Type].[All Store Type].[Deluxe Supermarket]).item(1)} on COLUMNSFROM [Warehouse]WHERE [Measures].[Units Shipped]

  • Item (set version)Set.Item(String Expression[, String Expression...] | Index)Returns a tuple specified by the String Expression of the function arguments.String Expression can either define a complete tuple expression or a series of individual members for each dimension used (in order) by the set.SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {CrossJoin([Time].[Quarter].Members, [Product].[Product Family].Members).Item("[1998].[Q1]","Food")} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

    OR

    SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {CrossJoin([Time].[Quarter].Members, [Product].[Product Family].Members).Item(([1998].[Q1],Food)")} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

  • Functions (a small subset)Ancestor()Cousin()ParallelPeriod()PeriodsToDate() LastPeriods() Sum()Order()Union()Filter()CrossJoin()Subset()Generate()TopCount()

  • AncestorAncestor(Member, Distance)Ancestor(Member, Level)Returns the member at the level or distance specified relative to the specified Member.SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {Ancestor([Time].[1998].[Q2].[5], 2)} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

    OR

    SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {Ancestor([Time].[1998].[Q2].[5], [Time].[Year])} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

  • CousinCousin(Member1, Member2)Find the member in the same relative position as Member1 given a new parent member, Member2.SELECT {Cousin([Time].[1997].[Q1],[Time].[1998])} ON COLUMNSFROM [Warehouse]

  • ParallelPeriodParallelPeriod([Level[, Numeric Expression[, Member] ] ])Similar to CousinReturns a member in the same relative position as Member but with an ancestor at Level that is Numeric Expression away from the ancestor of Member.SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {ParallelPeriod([Time].[Year], 1, [Time].[1998].[Q2].[5])} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

  • PeriodsToDatePeriodsToDate([Level[, Member] ])Returns all the members from the start of Level up to and including MemberSELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {PeriodsToDate([Time].[Year], [Time].[1998].[Q2].[5])} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

  • LastPeriodsLastPeriods(Index[, Member])Returns a number of members, specified by Index and from the same level as Member, up to and including Member.SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {LastPeriods(3, [Time].[1998].[Q2].[5])} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

  • SumSum(Set[, Numeric Expression])Aggregates the numeric values from Numeric Expression which are returned for each of the members of Set.WITH MEMBER [Measures].[ToDate] AS 'SUM(PeriodsToDate([Time].[Year],[Time].[1998].[Q3].[7]),[Measures].[Warehouse Sales])'SELECT {[Measures].[ToDate]} ON COLUMNS, {[Store].[Store Country].members} ON ROWSFROM [Warehouse]

  • SUM WorkshopFill in the expressions to populateYear to DatePrior Year to DateRolling average of the Last 6 Months

    WITH MEMBER [Measures].[YTD] AS '[Measures].[Units Shipped]' MEMBER [Measures].[Prior YTD] AS '[Measures].[Units Shipped]'

    MEMBER [Measures].[Last 6 Months - SUM] AS '[Measures].[Units Shipped]'

    SELECT { [Time].[Month].Members} ON ROWS, { [Measures].[Units Shipped],[Measures].[YTD], [Measures].[Prior YTD], [Measures].[Last 6 Months - SUM]} ON COLUMNSFROM Warehouse

  • OrderOrder(Set, {String Expression | Numeric Expression}[, ASC | DESC | BASC | BDESC])Sorts the set of members from SetASC and DESC respect the order of the hierarchy and sorts within this structure.BASC and BDESC will Break the hierarchy and sort by the expression only.SELECT {[Measures].[Units Shipped]} ON COLUMNS, { ORDER({[Store].[Store Country].Members, [Store].[Store State].members}, ([Measures].[Units Shipped]) , DESC)} ON ROWSFROM [Warehouse]WHERE [Time].[1998]

  • UnionUnion(Set1, Set2[, ALL])Combines two individual sets to return one set as a resultAlternate syntax 1 (Union): {Set1 + Set2}Alternate syntax 2 (Union All): {Set1 , Set2}SELECT {[Measures].[Units Shipped]} ON COLUMNS, UNION([Store].[Store Country].Members, [Store].[Store State].members) ON ROWSFROM [Warehouse]WHERE [Time].[1998]

  • FilterFilter(Set, Search Condition)Returns the members of Set for which the Search Condition is true.SELECT {[Measures].[Units Shipped]} ON COLUMNS, FILTER([Store].[Store State].members,[Measures].[Units Shipped]>0) ON ROWSFROM [Warehouse]WHERE [Time].[1998]

    SELECT {[Measures].[Units Shipped]} ON COLUMNS, FILTER([Store].[Store State].members,[Measures].[Units Shipped]>25000) ON ROWSFROM [Warehouse]WHERE [Time].[1998]

  • CrossjoinCrossjoin(Set1, Set2)Returns a set of tuples defined by the matching of all members in Set1 to all the members in Set2NON EMPTY can be used to eliminate empty intersections. Alternately, NonEmptyCrossJoin() can be used.SELECT { CROSSJOIN([Store].[Store Country].members,[Time].[Year].Members)} ON ROWS, { [Measures].[Units Shipped]} ON COLUMNSFROM Warehouse

  • TopCountTopCount(Set, Count[, Numeric Expression])Returns the first Count members from Set after sorting them in descending order based on Numeric Expression.SELECT { TopCount([Store].[Store City].members,10,[Measures].[Units Shipped])} ON ROWS, { [Measures].[Units Shipped]} ON COLUMNSFROM Warehouse

  • GenerateGenerate(Set1, Set2[, ALL])Generate(Set1, String Expression[, Delimiter])Evaluates Set2 or the String Expression for each member of Set1.SELECT { GENERATE([Product].[Product Family].members,TopCount(Descendants([Product].currentMember,[Product].[Product Name]),2,[Measures].[Units Shipped]))} ON ROWS, { [Measures].[Units Shipped]} ON COLUMNSFROM Warehouse

    The SELECT clause defines the contents of the axes.The FROM clause defines the connection to the cube or OLAP source.The WHERE clause defines the slicer or context based on members and member sets.

    MDX results are a smaller multi-dimensional cube derived from the original cube source. SQL results are columnar and only ever define a single axis.

    Exercise:

    From the Warehouse cube, select the Drink Product Family on the rows and select the Store Invoice measure on the columns.

    SELECT {[Product].[All Products].[Drink]} on ROWS,{[Measures].[Store Invoice]} on COLUMNSFROM WarehouseExercise:

    Modify the prior exercise to put the Store Invoice measure in the where clause and select the Drink Product Family on the Columns (no rows).

    SELECT {[Product].[All Products].[Drink]} on COLUMNSFROM WarehouseWHERE [Measures].[Store Invoice]Exercise:

    From the Warehouse cube, use the above select statement as the starting point for the rows and columns. Define a new measure called Sales Tax as Warehouse Sales multiplied by 0.15

    WITH MEMBER [Measures].[Sales Tax] AS '[Measures].[Warehouse Sales] * 0.15'SELECT {([Time].[1998].children)} ON COLUMNS, {([Warehouse].[Country].members)} ON ROWSFROM WarehouseWHERE [Measures].[Sales Tax]Exercise:

    Using the prior example results, comment out the definition of Sales Tax and write a new version of Sales Tax that multiplies Warehouse Sales by 1.15 instead of 0.15

    WITH // MEMBER [Measures].[Sales Tax] AS '[Measures].[Warehouse Sales] * 0.15'MEMBER [Measures].[Sales Tax] AS '[Measures].[Warehouse Sales] * 1.15'SELECT {([Time].[1998].children)} ON COLUMNS, {([Warehouse].[Country].members)} ON ROWSFROM WarehouseWHERE [Measures].[Sales Tax]Only required when the tuples/members are explicitly listed.

    Some Function/Method calls can be used to produce sets of members directly and the {} may be left out.

    Exercise:

    With the prior example results, replace the rows with the Sales Tax measure. Using a set expression, add the original Warehouse Sales measure to the rows before Sales Tax.

    WITH MEMBER [Measures].[Sales Tax] AS '[Measures].[Warehouse Sales] * 1.15'SELECT {([Time].[1998].children)} ON COLUMNS, {[Measures].[Warehouse Sales], [Measures].[Sales Tax]} ON ROWSFROM Warehouse

    As an additional exercise, modify the Columns to be the set of Q4 from 1997 and Q4 from 1998.

    WITH MEMBER [Measures].[Sales Tax] AS '[Measures].[Warehouse Sales] * 1.15'SELECT {[Time].[1997].[Q4],[Time].[1998].[Q4]} ON COLUMNS, {[Measures].[Warehouse Sales], [Measures].[Sales Tax]} ON ROWSFROM Warehouse

    The MSAS MDX Sample Application will merge the heading of the two columns into one cell. This is because the Sample Application is not very smart and is trying to make assumptions for you. The members still exist as distinct entities although the headings are merged.

    Exercise:

    From the Warehouse cube select the set of all product family members on the rows and Canada from the Store country on the columns. In the where clause specify the Units Shipped measure.

    SELECT {[Store].[All Stores].[Canada]} ON COLUMNS, {[Product].[All Products].[Drink], [Product].[All Products].[Food], [Product].[All Products].[Non-Consumable]} ON ROWSFROM WarehouseWHERE [Measures].[Units Shipped]

    Run the query and notice that there are no measure values. This is because the default member of the time dimension is 1997 and there are no units shipped for Canada in 1997. Most hierarchies will have a root member that allows for rollup of all values to a single root ancestor. The time dimension in the Foodmart samples is an exception to this and there is no root member here. Since there is no root member there is no automatic rollup of all time periods to get an overall total for all years.

    Use a tuple to specify that the context of the query should be the intersection of Units Shipped and the year 1998

    SELECT {[Store].[All Stores].[Canada]} ON COLUMNS, {[Product].[All Products].[Drink], [Product].[All Products].[Food], [Product].[All Products].[Non-Consumable]} ON ROWSFROM WarehouseWHERE ([Measures].[Units Shipped], [Time].[1998])

    Now values are returned because there are units shipped for Canada in 1998.Exercise:

    Using the results of the prior exercise, remove Canada from the Columns and edit the query so that the tuple from the Where clause becomes the new column definition.

    SELECT {([Measures].[Units Shipped], [Time].[1998])} ON COLUMNS, {[Product].[All Products].[Drink], [Product].[All Products].[Food], [Product].[All Products].[Non-Consumable]} ON ROWSFROM Warehouse

    Notice in the results that 1998 is nested beneath Units Shipped. The order of the arguments for the tuple function defines the order of the nesting in the sample application.Exercise:

    Use the above select statement as the basis for this exercise. Replace the Rows with the range of all product brand names from the first instance of Pearl to the second instance of Walrus.

    SELECT { [Measures].[Store Invoice]: [Measures].[Warehouse Profit]} ON COLUMNS, { [Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Beer].[Pearl] :[Product].[All Products].[Drink].[Alcoholic Beverages].[Beer and Wine].[Wine].[Walrus]} ON ROWSFROM WarehouseWHERE ([Warehouse].[All Warehouses].[USA].[CA])Exercise:

    Use the above select statement as the basis for this exercise. Ask the students why there are no values displayed for Canada. The answer is that the default time member, 1997, is being used and there are no Units Shipped or Units Ordered for Canada in 1997.

    Apply the NON EMPTY clause before [Store].Members.

    SELECT { [Measures].[Units Shipped], [Measures].[Units Ordered] } ON COLUMNS, NON EMPTY [Store].Members ON ROWSFROM [Warehouse]

    Use a where clause to specify 1998 and notice that the Canadian entries are now displayed because they are no longer empty.

    SELECT { [Measures].[Units Shipped], [Measures].[Units Ordered] } ON COLUMNS, NON EMPTY [Store].Members ON ROWSFROM [Warehouse]WHERE [Time].[1998]

    [Bellmont Distributing] is a warehouse in Vancouver. The parent of [Dairy] ([Dairy].parent) is Drink but this is misleading because [Dairy] exists in many other places in the Product tree such as under Food and also under Dairy itself. Note that MSAS does not enforce uniqueness via the aliases in the Sample Application.There are two possible answers for this depending on whether the students select [Drink] or [Drinks]. For Drink the results will be: Alcoholic Beverages, Beverages, and Dairy. For Drinks the answer will be Flavored Drinks.The answer will be 1The answer will be 12 but if an initial year is not specified then this will be month 12 of the default time member, 1997 rather than 1998. To get the LastSibling of 1998 you need to specify 1998 or use the lastSibling of the default member (1997 is the default and the lastSibling is 1998) and then use lastChild to move down the tree from 1998.DFZacatecas[Store].[Store City].members and [Time].members. Note that when applied to a dimension/hierarchy all members of all levels are returned while when applied to a level only the members of that level are returned.1998PrevMember task will return an error because there are no previous members available.

    Exercise:

    From the Warehouse cube, select all the years on the columns and all the warehouse countries on the rows. Use the WITH MEMBER to define a measure for your WHERE clause that subtracts the Units Shipped for 1998 from the value for the current member of the time dimension.

    WITH MEMBER [Measures].[Diff from 1998] AS '([Measures].[Units Shipped], [Time].currentMember) - ([Measures].[Units Shipped], [Time].[1998])'SELECT {[Time].[Year].members} ON COLUMNS, {([Warehouse].[Country].members)} ON ROWSFROM WarehouseWHERE [Measures].[Diff from 1998]

    Notice that the results in the 1998 column are blank because the result of the calculation is zero. We also know that Canada (and Mexico) have no Units Shipped in 1997 so the negative values that show up in the 1997 column represent the subtracted 1998 values only.

    WITH MEMBER [Measures].[YOY Variance] AS '([Time].currentMember,[Warehouse].currentMember,[Measures].[Warehouse Sales])-([Time].currentMember.prevMember,[Warehouse].currentMember,[Measures].[Warehouse Sales])'SELECT {([Time].[Year].members)} ON COLUMNS, {([Warehouse].[Country].members)} ON ROWSFROM WarehouseWHERE ([Measures].[YOY Variance])Exercise:

    Select the third child of the year 1998.

    SELECT {[Time].[Year].[1998].children.item(3)} ON COLUMNSFROM Warehouse

    Exercise:

    Find the ancestor of Milk at the first level in the hieararchy.

    SELECT {Ancestor([Milk],3)} ON COLUMNSFROM Warehouse

    OR

    SELECT {Ancestor([Milk],[Product].[Product Family])} ON COLUMNSFROM WarehouseExercise:

    Find the cousin of [Carbonated Beverages] (under the Drink Product Family) in the Food product family.

    SELECT {Cousin([Product].[All Products].[Drink].[Beverages].[Carbonated Beverages], [Product].[All Products].[Food])} ON COLUMNSFROM Warehouse

    The result is Baked Goods. Carbonated Beverages is the second member under Drinks at the Product Category level. Baked Goods is likewise the second member at the Product Category level under the Food product family.Exercise:

    From December of 1997 find the parallel period from 2 quarters prior and from two quarters in the future.

    SELECT {ParallelPeriod([Time].[Quarter],2,[Time].[1997].[Q4].[12])} ON COLUMNSFROM Warehouse

    The result is month 6 from 1997And

    SELECT {ParallelPeriod([Time].[Quarter],-2,[Time].[1997].[Q4].[12])} ON COLUMNSFROM Warehouse

    The result is month 6 from 1998Exercise:

    The above is a Year To Date. Find the Quarter To Date from month 5 of 1998.

    SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {PeriodsToDate([Time].[Quarter], [Time].[1998].[Q2].[5])} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

    Exercise:

    Find the Last 5 Quarters from Q3 of 1998.

    SELECT {[Warehouse].[All Warehouses].[Canada]} on COLUMNS, {LastPeriods(5, [Time].[1998].[Q3])} on ROWSFROM [Warehouse]WHERE [Measures].[Units Shipped]

    If this slide is going to be a demo only then build the above example up using the following as your starting point to show all the months of the Year To Date range:

    SELECT {PeriodsToDate([Time].[Year],[Time].[1998].[Q3].[7])} ON COLUMNS, {[Store].[Store Country].members} ON ROWSFROM [Warehouse]WHERE [Measures].[Warehouse Sales]

    Remind students that the syntax for SUM, LastPeriods, PeriodsToDate, and ParallelPeriod can all be obtained by dragging in the functions from the Syntax Examples frame of the MDX Sample Application.

    Solution

    WITH MEMBER [Measures].[YTD] AS 'SUM(PeriodsToDate([Time].[Year],[Time].currentMember),[Measures].[Units Shipped])' MEMBER [Measures].[Prior YTD] AS 'SUM(PeriodsToDate([Time].[Year],ParallelPeriod([Time].[Year],1,[Time].currentMember)),[Measures].[Units Shipped])'

    MEMBER [Measures].[Last 6 Months - AVG] AS 'AVG(LastPeriods(6,[Time].currentMember),[Measures].[Units Shipped])'

    SELECT { [Time].[Month].Members} ON ROWS, { [Measures].[Units Shipped],[Measures].[YTD], [Measures].[Prior YTD], [Measures].[Last 6 Months - AVG]} ON COLUMNSFROM WarehouseExercise:

    Build the results above in a step by step process. Start from:

    SELECT {[Measures].[Units Shipped]} ON COLUMNS, {[Store].[Store Country].members,[Store].[Store State].members} ON ROWSFROM [Warehouse]WHERE [Time].[1998]

    Notice that all the countries are listed at the top in the order from the cube: Canada, Mexico, USA.

    Apply the Order function to order based on Units Shipped.

    SELECT {[Measures].[Units Shipped]} ON COLUMNS, ORDER({[Store].[Store Country].members,[Store].[Store State].members},[Measures].[Units Shipped], desc) ON ROWSFROM [Warehouse]WHERE [Time].[1998]

    Modify the order function to use leverage the caption of the Store member to sort the records. First step is to develop the caption for sorting. This can be done with the Name property of the currentMember reference, [Store].currentMember.Name :

    SELECT {[Measures].[Units Shipped]} ON COLUMNS, { ORDER({[Store].[Store Country].Members, [Store].[Store State].members}, [Store].currentmember.name , DESC)} ON ROWSFROM [Warehouse]WHERE [Time].[1998]

    Notice that USA is followed by the States within USA. The hierarchy is being respected and the States are kept with the appropriate Country. Use BDESC to break the hierarchy

    SELECT {[Measures].[Units Shipped]} ON COLUMNS, { ORDER({[Store].[Store Country].Members, [Store].[Store State].members}, [Store].currentmember.name , BDESC)} ON ROWSFROM [Warehouse]WHERE [Time].[1998]

    Now notice that the state of Zacatecas is first in the results (based on descending order).Exercise:

    Create a union of all Year and Month members.

    SELECT {[Time].[Year].members,[Time].[Month].members} on ROWS, {[Measures].[Units Shipped]} on COLUMNSFROM Warehouse

    Create a union of the Year members and the Product Family members.

    SELECT {[Time].[Year].members,[Product].[Product Family].members} on ROWS, {[Measures].[Units Shipped]} on COLUMNSFROM Warehouse

    An error will occur because the two sets in the Union are not from the same hierarchy.Exercise:

    Find all the Product Category members that Shipped more than 1000 Units in 1997

    SELECT {FILTER([Product].[Product Category].members,[Measures].[Units Shipped] > 1000)} on ROWS, {[Measures].[Units Shipped]} on COLUMNSFROM WarehouseWHERE [Time].[Year].[1997]

    Use a tuple to now find all the Product Categroy members that Shipped more than 1000 Units in 1998 and display the value for the Units Shipped in 1997.

    SELECT {FILTER([Product].[Product Category].members,([Measures].[Units Shipped],[Time].[Year].[1998]) > 1000)} on ROWS, {[Measures].[Units Shipped]} on COLUMNSFROM WarehouseWHERE [Time].[Year].[1997]

    The results will show several members in 1997 that have less than 1000 Units Shipped because the filter is applied to the 1998 data only.Notice that the filter can operate independently of the current context of the query.Exercise:

    Create a simple selection of all Product Name members on the rows and Units Shipped on the columns.

    SELECT {[Product].[Product Name].members} on ROWS, {[Measures].[Units Shipped]} on COLUMNSFROM Warehouse

    Notice that this query is quick. Create the crossjoin between the Product Name members and all the members of the Month level from the Time dimension.

    SELECT {CROSSJOIN([Product].[Product Name].members,[Time].[Month].members)} on ROWS, {[Measures].[Units Shipped]} on COLUMNSFROM Warehouse

    Notice that the query takes a couple of seconds to return. Apply the NON EMPTY condition to the CrossJoin.

    SELECT NON EMPTY {CROSSJOIN([Product].[Product Name].members,[Time].[Month].members)} on ROWS, {[Measures].[Units Shipped]} on COLUMNSFROM Warehouse

    Notice that the query is considerably quicker than before. The empty cells need not be created/calculated and only the values stored in the cube need to be retrieved.

    Analysis Services 2000 does not allow a crossjoin between sets from the same dimension (i.e. showing months below years). Analysis Services 2005 should allow you to do this operation. However, you can display a text string listing the parent/ancestor of the current member on the rows to show the year for each month.

    WITH MEMBER [Measures].[Year Name] as 'Ancestor([Time].currentMember, [Time].[Year]).Name'SELECT {[Time].[Month].members} on ROWS, {[Measures].[Year Name], [Measures].[Units Shipped]} on COLUMNSFROM Warehouse

    Note that this prevents the use of NON EMPTY to eliminate empty measure cells because the text measure created for the Year Name will never be empty. The filter function would need to be used to eliminate empty results and this will perform less efficiently than the NON EMPTY clause.

    Also, Cognos 8 leverages member properties rather than text measures to display the resulting nesting in reports.Exercise:

    Use BottomCount to find the 2 worst Months for Warehouse Sales.

    SELECT {BottomCount([Time].[Month].members,2,[Measures].[Warehouse Sales])} on ROWS, {[Measures].[Warehouse Sales]} on COLUMNSFROM Warehouse

    Bonus Exercise:

    Use the descendants function to get the months of 1998 only. See the Syntax Examples section of the MDX Sample Application for the required syntax.

    SELECT {BottomCount(descendants([Time].[Year].[1998],[Time].[Month]),2,[Measures].[Warehouse Sales])} on ROWS, {[Measures].[Warehouse Sales]} on COLUMNSFROM Warehouse

    Since both month numbers change we can safely assume that the months in the first example were from 1997 although they arent displayed as such in the first query results. The MDX Sample application does allow you to double click on a member in the results pane to get detail properties though.

    We could have also used the text measure technique from the notes of the CROSSJOIN slide to list the year.Exercise:

    List the bottom 2 months based on Units Shipped for each year.

    WITH MEMBER [Measures].[Year Name] as 'Ancestor([Time].currentMember, [Time].[Year]).Name'SELECT { GENERATE([Time].[Year].members,BottomCount(Descendants([Time].currentMember,[Time].[Month]),2,[Measures].[Units Shipped]))} ON ROWS, {[Measures].[Year Name], [Measures].[Units Shipped]} on COLUMNSFROM Warehouse