You are on page 1of 54

Page 1 of 13

http://www.sqlservercentral.com/articles/Stairway+Series/71867/
Printed 2011/07/07 08:08AM

Stairway to MDX - STEP 1: Getting Started with MDX


By Bill_Pearson, 2010/12/08
To learn MDX, there is really no alternative to installing the system and trying out the statements, and experimenting. William E Pearson, the well-known expert on MDX, kicks off a stairway series on this important topic by getting you running from a standing start.

Contents
Step 1: Getting Started with MDX Installing Analysis Services 2008R2 and Samples Accessing an MDX Editor Creating an MDX query Introduction Syntax Trying things out: A few initial queries Procedure: Satisfy Business Requirements with MDX Summary...

Step 1: Getting Started with MDX


MDX, which stands for MultiDimensional eXpressions, is a language with a specialized syntax for querying and manipulating the multidimensional data stored in OLAP cubes. Since it first appeared in Microsoft OLAP Services 7.0 in 1998, a number of other products have adopted it. In this series, well be getting to the stage of being able to create useful MDX queries in a business context, and well move on from that point to give you a comprehensive understanding of the functions, operators, and properties of MDX. The objective will be to encourage you to take the example code as you read the steps, and try it out, making changes and experimenting, so as to get the feel for all the features of MDX. Well illustrate every point with practice examples of the business uses along with useful queries. Try them out. To do this, you need to have installed at least the Analysis Services component of SQL Server 2005 or above. The full installation of SQL Server 2005 and beyond allows for virtually any exercise we might undertake, including occasional references to Reporting Services and other layers of the solution primarily to illustrate the purpose of the queries and the datasets that they retrieve, although the majority of our sessions center on Analysis Services and its underlying components (cubes, dimensions, measures, and such). For purposes of the series, you should install, or have access to, SQL Server 2008R2, and, specifically, the Analysis Services components of the release (I will often substitute the term Analysis Services from now on). You will also need the appropriate access rights to the sample cubes provided in a default installation of Analysis Services. Installation of Analysis Services from the Standard edition of SQL Server 2008R2 will be adequate for the vast majority of our activities, although the Developer / Enterprise edition is certainly ideal. I will provide references for step-by-step installation of SQL Server 2008R2 Developer / Enterprise in the section that follows. It is also assumed that the computer(s) involved meet the system requirements, including hardware and operating systems, of the applications we have mentioned.

Important Note: If you have no alternative except to work with Analysis Services 2005 or 2008, the practice exercises of this series can perhaps be meaningfully completed with modification of the queries to compensate for differences in the data structures of the sample cube among the versions although you may find this requirement cumbersome and distracting. Because both the relational databases and the Analysis Services samples for 2008R2 differ somewhat from those of previous releases (the best example of

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 2 of 13

this is that the Analysis Services date dimension, as well as the supporting relational data, has been advanced into later operating years of the Adventure Works organization) the sample MDX syntax that we construct together will, when executed, deliver results which, based upon the 2008R2 samples, will differ from those based upon the previous releases. While you can adjust your own steps to make up for these differences (perhaps by checking your answers independently), you will not have the added comfort of the instant corroboration available in simply comparing your results to those presented in the images and explanations I present in the exercises. Consider working, therefore, with 2008R2, if at all possible: learning the basics of MDX is challenging enough for most that are new to it, without the additional distractions imposed by working with older releases. Additional Note: The screen captures in this series, until further notice, are made from a Windows 7 environment, so what you see on your own machine may differ somewhat, if you are working within another environment.

Installing Analysis Services 2008R2 and Samples


SQL Server 2008 and 2008R2 each provide a virtually identical single Setup program from which you can install any or all of its components, including Analysis Services. Using the unified Setup, you can install Analysis Services with or without other SQL Server components on a single computer. It is important, however, to understand that Analysis Services relies upon other components of SQL Server: for example, the Adventure Works cube (which resides within the Adventure Works DW 2008R2 Analysis Services database), uses the AdventureWorksDW2008R2 relational data mart in SQL Server as its data source, so, if we want to process the Analysis Services database and its cube (we cannot query an unprocessed cube), we will need to have access to its underlying relational data source and, therefore, to SQL Server and the associated sample database. There are many possible considerations in the installation of Analysis Services, depending upon the version(s) you intend to install, the hardware in your local environment, applications you may already have in place, and so forth. Rather than trying to reproduce them all in this article, we provide the following link, which covers this subject thoroughly, yet efficiently. Considerations for Installing Analysis Services Once you have determined the components you need to install, you can follow step-by-step instructions on how to start Setup, and to select the components you want to install, by following this link: Quick-Start Installation of SQL Server 2008 Once you have successfully installed Analysis Services(along with any other components you have chosen from the Setup program), you are ready to download and install the samples that we will be working with in this series. A great summary of the options that are available (based upon your SQL Server version and other considerations) can be found at: How to install Adventure Works SQL DW and Analysis Services 2005/2008 sample database and project

Accessing an MDX Editor


Well be introducing functions, operators, and other components in a number of sample sessions, using the types of queries that you might come across in your work. Ill use SQL Server Management Studio to create and execute these queries, so it is easiest to follow what I do with that, although you can certainly use any compatible editor you choose, instead. To prepare SQL Server Management Studio for writing, modifying and executing MDX queries, and examining the results returned within a practice session, take the following simple steps. 1. 2. 3. Click the Start button on the PC. Select Microsoft SQL Server 2008 within the Program group of the menu. Click SQL Server Management Studio, as shown in Illustration 1.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 3 of 13

Illustration 1: Opening SQL Server Management Studio

The Connect to Server dialog appears, after the brief Management Studio splash screen. 4. 5. 6. Select Analysis Services in the Server type selector Type / select the server name (server name / instance, if appropriate) in the Server name selector. Supply authentication information, as required in your own environment. The Connect to Server dialog appears similar to that depicted in Illustration 2.

Illustration 2: Connecting to the Server

7.

Click the Connect button to connect with the specified Analysis Services server. The SQL Server Management Studio opens.

8.

In the Object Explorer pane (it appears by default on the left side of the Studio), expand the Databases folder (click the + sign to its immediate left), appearing underneath the Analysis Server within which we are working. The Databases folder opens, exposing the detected Analysis Services database(s), as shown in Illustration 3.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 4 of 13

Illustration 3: Exposing the Analysis Services Databases in the Object Browser

NOTE: The Analysis Services databases that appear will depend upon the activities that have taken place in your own environment, and will likely differ from those shown in Illustration 3 above. For purposes of the practice sessions in this article, the Adventure Works DW 2008R2 database must be present. If this is not the case, consult the Books Online for the installation / connection procedures, and complete these procedures before continuing.

9.

Expand the Adventure Works DW 2008R2 database. The Database expands, exposing the folders for the various objects housed within the Analysis Services database, as depicted in Illustration 4.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 5 of 13

Illustration 4: Exposing the Object Folders in the Database

10.

Expand the Cubes folder within the Adventure Works DW 2008 database. The Cubes folder opens. You may see multiple cubes here, depending upon your local environment. Adventure Works is the sample cube with which I will be conducting the practice exercises. The cubes appear similar to those shown in Illustration 5, within an out-of-the-box installation.

Illustration 5: The Cubes Appear

11. 12.

Click the Adventure Works cube to select it. Click the New Query button just under the main menu, in the upper left corner of the Management Studio, as depicted in Illustration 6.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 6 of 13

Illustration 6: Click the New Query Button with the Adventure Works Cube Selected

The Metadata pane for the Adventure Works cube appears, along with the Query pane to its right, as seen in Illustration 7.

Illustration 7: Adventure Works Cube Metadata Appears

We will be using the Query pane to construct and execute MDX queries throughout the practice sessions of this series.

Creating an MDX query


Introduction
MDX emerged circa 1998, when it first began to appear in commercial applications. MDX was created to query OLAP databases, and has become widely adopted within the realm of analytical applications. Based upon the XML for Analysis (XMLA) specification, with specific extensions for Analysis Services, MDX is the query language that has been specially designed to retrieve multidimensional data, among other activities, in Analysis Services. The components of Multidimensional expressions can be evaluated by Analysis Services to retrieve an object (for example a set or a member), or a scalar value (for example, a string or a number), and consist of identifiers, values, statements, functions, and operators. MDX expressions and queries can be used for numerous activities, including: Returning data to a manual editor or client application from an Analysis Services cube; Formatting query results; Performing cube design tasks, including the definition of calculated members, named sets, scoped assignments, and key performance indicators (KPIs); Performing administrative tasks, including dimension and cell security.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 7 of 13

Youll notice, at first blush, that MDX appears similar to the SQL syntax that is typically used with relational databases. Because MDX is not an extension of the SQL language, and is different from SQL in many ways, youll need to understand the basic concepts in MDX and dimensional modeling if you intend to work with MDX expressions to design or secure cubes, or to construct MDX queries to return and format multidimensional data. This will include MDX syntax elements, MDX operators, MDX statements, and MDX functions.

Syntax
The basic MDX query contains the SELECT statement: a SELECT query is the most frequently used query in MDX. You can gain a good understanding of the use of MDX to query multidimensional data through a grasp of three concepts: How an MDX SELECT statement must specify a result set; What the syntax of the SELECT statement is; and How to create a simple query using the SELECT statement.

Specifying a Result Set


In MDX, the SELECT statement specifies a result set that contains a subset of multidimensional data that has been returned from a cube. To specify a result set, an MDX query must contain the following information: The number of axes or sets of hierarchies. (You can specify up to 128 axes in an MDX query, although it is extremely rare to see one with greater than five axes.) The members from each dimension to include on each axis of the MDX query. The name of the cube that sets the context of the MDX query. The members from a slicer axis on which data is sliced for members specified within the query axes. To identify the query axes, the cube that sets the context of the query, and the slicer axis, the MDX SELECT statement uses the following clauses: A SELECT clause - determines the query axes of the SELECT statement. A FROM clause - determines which multidimensional data source to use when extracting data to populate the result set of the SELECT statement. A WHERE clause (optional) - determines which dimension or member to use as the slicer axis that restricts the extracting of data to a specific dimension or member.

SELECT Statement Syntax


The following syntax shows a basic SELECT statement that includes the use of the SELECT, FROM, and WHERE clauses:

[ WITH <SELECT WITH clause> [ , <SELECT WITH clause> ... ] ] SELECT [ * | ( <SELECT query axis clause> [ , <SELECT query axis clause> ... ] ) ] FROM <SELECT subcube clause> [ <SELECT slicer axis clause> ] [ <SELECT cell property list clause> ]

The above shows how the core MDX SELECT statement supports additional, optional syntax, such as the WITH keyword, the use of MDX functions to construct members by calculation for inclusion in an axis or slicer axis, and the ability to return the values of specific cell properties as part of the query. The following example much more like the syntax you can expect to encounter in exploring expressions within this series - shows a basic MDX query that uses the SELECT statement. This query returns a result set that contains the calendar years 2006 and 2007 Internet Sales Amount and Internet Order Quantity for the Australian customer base.

SELECT { [Measures].[internet Sales Amount], [Measures].[Internet Order Quantity] } ON COLUMNS,

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 8 of 13

{ [Date].[Calendar].[Calendar Year].[CY 2006], [Date]. [Calendar].[Calendar Year].[CY 2007] } ON ROWS FROM [Adventure Works] WHERE ([Customer].[Customer Geography].[Country].[Australia])

In this example, the query defines the following result set information: The SELECT clause sets the query axes: Internet Sales Amount and Internet Order Quantity members of the Measures dimension (on columns of the results dataset), and the 2006 and 2007 members of the Date dimension (on rows of the results dataset). The FROM clause indicates that the data source is the Adventure Works cube. The WHERE clause defines the slicer axis as the Australia member of the Customer dimension (Customer Geography hierarchy). While the query example uses the COLUMNS and ROWS axis aliases, you can also use the ordinal positions for these axes (as I virtually always do in my articles and in my work with clients). The following example shows how the MDX query could have been written to use the ordinal position of each axis:

SELECT { [Measures].[internet Sales Amount], [Measures].[Internet Order Quantity] } ON AXIS (0), { [Date].[Calendar].[Calendar Year].[CY 2006], [Date]. [Calendar].[Calendar Year].[CY 2007] } ON AXIS (1) FROM [Adventure Works] WHERE ([Customer].[Customer Geography].[Country].[Australia] )

Using either of the query examples, you would obtain the results shown in Illustration 8.

Illustration 8: Results of Example Queries

Trying things out: A few initial queries


Procedure: Satisfy Business Requirements with MDX
We will be using SQL Server Management Studio to access the sample Adventure Works cube in the Adventure Works DW 2008 Analysis Services database. Ive already explained how to get this far. You can create an MDX query, execute it, and see the results in a grid-like results pane. For purposes of our practice session, assume that you have been given a business requirement by a hypothetical client. You have been asked by a representative information consumer within the client organization (Adventure Works) to provide the total Internet Sales Amounts and Internet Order Quantities, for the years 2006 and 2007 individually, for all customers in the United Kingdom. You are asked, moreover, to provide the information in a twodimensional grid, with the Internet Sales Amount and Internet Order Quantity measures in the columns, and the calendar years (2006 and 2007) in the rows. 1) Type (or cut and paste) the following query into the Query pane:

-- ST_SMDX001: Basic Query SELECT {[Date].[Calendar].[Calendar Year].&[2006], [Date].[Calendar].[Calendar Year].&[2007]}

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 9 of 13

ON COLUMNS, {[Measures].[Internet Sales Amount], [Measures].[Internet Order Quantity]} ON ROWS FROM [Adventure Works] WHERE [Customer].[Customer Geography].[Country].&[United Kingdom]

NOTE: This example references dimension members in a different way than what we saw earlier. For example, when I referenced the Date dimension in the Syntax section above, I simply used the member names in the axis specification, as shown below.

{ [Date].[Calendar].[Calendar Year].[CY 2006], [Date]. [Calendar].[Calendar Year].[CY 2007] } ON ROWS

When I referenced the Date dimension in the query above, however, I resolved the members uniquely by using their keys. To reference a member by key, you prefix the key with the ampersand (&) symbol.

{[Date].[Calendar].[Calendar Year].&[2006], [Date].[Calendar].[Calendar Year].&[2007]}

The reason I focus upon this at present is that, when you drag the member from the Metadata tab to the Query pane, instead of simply typing the name, the key is what is inserted on the canvas. Moreover, using the key versus the name means that, even if multiple members have the same name, the member will be resolved uniquely by Analysis Services. (I will use both approaches throughout this series.) The diagram below labels some of the parts of the query:

Illustration 9: Labeled Parts of a Basic MDX Query

The following general discussion items apply to the syntax above, as well as to MDX queries in general: The top line of the query is a comment. The two dashes (--) represent one of three typical ways to place a comment in MDX syntax, so that it is ignored when the MDX is parsed. The cube that is targeted by the query (the query scope) appears in the FROM clause of the query. The FROM clause in MDX works much as it does in SQL (Structured Query Language), where it stipulates the tables used as sources for the query.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 10 of 13

The query syntax also uses other keywords that are common in SQL, such as SELECT and WHERE. Even though there are apparent similarities in the two languages, there are also significant differences. A prominent difference is that the output of an MDX query, which uses a cube as a data source, is another cube, whereas the output of an SQL query (which uses a columnar table as a source) is typically columnar. It is important to realize that MDXs cube output allows you to place any dimension from the source cube onto any axis of the querys result cube. Many axes can exist, and it is often better to think in terms of axes than in dimensions (as is quite common among both developers and information consumers) when designing an MDX query. This is for two main reasons: The axes concept allows for distinction between the source dimensions and the apparent result cube dimensions, which may be very different, indeed. Another reason is that a given axis can contain a number of cube dimensions in combination/juxtaposition. Axis references are therefore more precise, and less subject to misinterpretation. A query has one or more axes. The query we constructed above has two. (The first three axes - ordinals 0 through 2 - that are found in MDX queries are known as columns, rows and pages.) We stipulated the axes above through our use of the columns and rows specifications. (We could also have done so via the axis ordinals, as I mentioned earlier, in the introduction we will use ordinals in the next example, and then in most examples going forward in this series). Keep in mind that columns always come before rows, and rows always precede pages, within the query. Curled brackets ( { } ) are used in MDX to represent a set of members of a dimension or group of dimensions. The simple query above has one dimension each on the two query axes. The dimensions that appear are the Measures and Date dimensions. You can display more than one dimension on a result axis. When you do this, an intersection occurs, in effect, and each cell appearing in the associated axis relates to the combination/ juxtaposition of a member from each of the indicated dimensions. When more than one dimension is mapped onto an axis, the axis is said to consist of tuples, containing the members of each of the mapped dimensions. Dimensions that are not specified within the axes of a query will have members specified by default; you can also stipulate such members in the WHERE clause, as shown in our query above. 2) Click the Execute (!) button just underneath the main menu (and above and to the right of the Object Explorer, assuming it is anchored in its default location on your local system), as shown in Illustration 10.

Illustration 10: Click the Execute (!) Button

The retrieved data appears on the Results tab, underneath the Query pane, as soon as Analysis Services fills the cells that it determines to be specified by the query. Your results should appear as depicted in Illustration 11.

Illustration 11: The Initial Query Results

3) Save the query by selecting File Save MDXQuery1.mdx (or similar name) As , and call the file SMDX001, as shown in Illustration 12.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 11 of 13

Illustration 12: Saving the MDX Query via the Save As Dialog

NOTE: Much rewriting and confusion between altered versions can be avoided by storing the queries in a logical system of some sort, to keep organized, and to use some sort of Source Control system.

Let's create another query to conclude this introductory session. This time, lets say that client information consumers have asked for a comparison between the total Reseller Sales for the first and second quarters of calendar year 2007. We will again create a query against the Adventure Works cube to generate this information. 4) Select File New from the main menu.

5) Select Query with Current Connection from the cascading menu that appears next, as depicted in Illustration 13.

Illustration 13: Create a New Query with the Current Connection

A new tab, with a connection to the Adventure Works cube (you can see it listed in the selector of the Metadata pane, as expected) appears in the Query pane. 6) Type (or cut and paste) the following query into the Query pane:

ST_SMDX002: Basic Query 2 SELECT {[Date].[Calendar].[Calendar Quarter].&[2007]&[1], [Date].[Calendar].[Calendar Quarter].&[2007]&[2]} ON AXIS (0),

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 12 of 13

{[Reseller].[Reseller Type].[All Resellers]} ON AXIS (1) FROM [Adventure Works] WHERE ([Measures].[Reseller Sales Amount])

The Query pane appears, with our input, as shown in Illustration 14.

Illustration 14: Our Second Query in the Query Pane

7) Execute the query by clicking the Execute (!) button in the toolbar. The Results pane is populated by Analysis Services, and the dataset depicted in Illustration 15 appears.

Illustration 15: Results of the Second Query

Because we have specified the Reseller Sales Amount measure in the WHERE statement, we have made it the slicer dimension. The slicer shows that we have picked only the Reseller Sales Amount measure from the measures dimension. We will work with slicer dimensions, as well as with the other components of the simple queries you have examined in this lesson, and far more, as we progress through the Stairway to MDX series. 8) Select File location. 9) Select File Save As, name the file ST_SMDX002, and place it with the first query in a meaningful

Exit to leave the SQL Server Management Studio, when ready.

Summary
With this article, I introduced the Stairway to MDX series. I began by noting that the series is designed to provide hands-on introduction to the basics of the Multi-Dimensional eXpressions (MDX) language, with each article progressively exposing an individual function or other component designed to meet specific real-world needs. One of my objectives is to make each lesson as standalone as possible, meaning that readers should rarely encounter cases where they cannot complete the practice steps of a given article without components or objects that they have created in previous articles (although I will provide meaningful cross-references, to direct readers to more information about functions and other components I have previously explored, and which the readers may be using in the context of the article at hand).

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 13 of 13

Copyright 2002-2011 Simple Talk Publishing. All Rights Reserved. Privacy Policy. Terms of Use. Report Abuse.

http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable

07/07/2011

Page 1 of 7

http://www.sqlservercentral.com/articles/MDX/72256/
Printed 2011/07/07 08:09AM

Stairway to MDX - STEP 2: The Ordinal Function


By Bill_Pearson, 2011/01/24
Business Intelligence Architect Bill Pearson introduces the MDX .Ordinal function, as a means for generating lists and for conditionally presenting calculations. He also demonstrates the use of the function in creating datasets to support report parameter picklists.

n SQL Server Analysis Services (SSAS), The MDX .Ordinal function is useful within many activities, from generating simple lists to supporting sophisticated conditional calculations and presentations, or even supporting parameter picklists. The purpose of the .Ordinal function is to return the ordinal value of a specified dimensional level. The .Ordinal function is particularly useful in combination with other functions such as the IIF() logical function. This allows us to drive conditional generation, and display, of calculations and other values.

The .Ordinal function, when acting upon a level expression, returns the zero-based index of the level expression to which it is appended with the period (.) delimiter Putting .Ordinal to work is straightforward. When using the function to return the value of the level with which it works, we simply append it to the right of the level. As an example, within a query executed against the sample Adventure Works cube, for a dimension named Sales Territory (with a hierarchy of the same name), with three levels, named Sales Territory Group, Sales Territory Country, and Sales Territory Region, the following pseudoexpression ...

[Sales Territory].[Sales Territory].[ Sales Territory Group].[North America].ORDINAL

...returns 1, the zero-based value (or index) of the Sales Territory Group level (the top Sales Territory level itself or All Groups is level 0). As another example, the following:

[Sales Territory].[Sales Territory].[ Sales Territory Region].[Central].ORDINAL

returns 3, the numeric value of the Sales Territory Region hierarchical level. The .Ordinal function is best used in combination with other functions, particularly relative functions, to generate lists of names, and so forth In using the .Ordinal function to return the associated level value, the level upon which we seek to apply the function is specified to the left of .Ordinal. The function takes the level expression to which it is appended as its argument, and returns a zero-based value for the level specified. The general syntax is shown in the following string:

<<Level_Expression >>.Ordinal

Lets try it out. If you are not sure how to set up SSMS in Analysis Services to access the Adventure Works DW 2008R2 database, then click here for a guide.

Using the .Ordinal Function to Generate a Self-Explanatory Contents Results Dataset


Lets construct a simple query to provide a conceptual starting point for the query that we will next provide for parameter picklist dataset support. The idea is to generate a dataset that displays the Name of the level and the zerobased number (or index) for each level, for a given dimensional hierarchy within the Adventure Works cube. This initial display will show the concepts behind using the .Ordinal function and, we hope, make clear some of the ways we can employ it effectively. Then well show how it can be extended to provide a parameter picklist support.

http://www.sqlservercentral.com/articles/MDX/72256/Printable

07/07/2011

Page 2 of 7

1.

Type (or cut and paste) the following query into the Query pane:
-- SMDX002-001 Initial "Starter Query" to Present a Hierarchical -Level Name and Number Display, using .Ordinal WITH MEMBER [Measures].[SalesTerrName] AS '[Sales Territory].[Sales Territory].CURRENTMEMBER.NAME' MEMBER [Measures].[SalesTerrLevNo] AS '[Sales Territory].[Sales Territory].CURRENTMEMBER.LEVEL.ORDINAL' SELECT {[Measures].[SalesTerrName], [Measures].[SalesTerrLevNo]} ON AXIS(0), {[Sales Territory].[Sales Territory].MEMBERS} ON AXIS(1) FROM [Adventure Works]

The Query pane appears, with our input.

Illustration 1: Our Initial Query in the Query Pane

The above query sets the stage for our demonstrations of some of the uses of .Ordinal. The idea is to simply generate a dataset that illustrates exactly the data that we can expect to see. 2. Execute the query by clicking the Execute button in the toolbar...

Illustration 2: Click Execute to Run the Query

The Results pane is populated by Analysis Services, and the dataset appears.

http://www.sqlservercentral.com/articles/MDX/72256/Printable

07/07/2011

Page 3 of 7

Illustration 3: Results Dataset Initial Listing Scenario

In the returned dataset, we see that the names, and respective index numbers, of the hierarchical levels appear as expected. This simple dataset provides a great beginner basis for picklist support, as the picklist display labels appear within it. The level values can serve as a basis for ordering the picklist display, and with minimal alteration, .Ordinal can be used (in conjunction with a little more logic in the query) to provide indentation based upon level, etc. 3. Select File -- Save MDXQuery1.mdx As location. , name the file SMDX002-001, and place it in a meaningful

Use the .Ordinal Function to Generate a Dataset to Support a Report Parameter Picklist
The point of our next effort is to generate the fields we need for report parameter picklist support, this time for the Geography dimension of the cube. The authors / developers have asked specifically for all geographical levels to show up as selections within the parameter picklists for various reports in SQL Server Reporting Services. When we venture upon parameter picklist support in an OLAP scenario (at least via this method), we need to provide two main ingredients within the returned dataset: a name that consumers can select at report runtime and the MDXequivalent, qualified name, which is passed to Analysis Services via placeholders in the underlying dataset query. An index (again, the zero-based numeric value of a given dimensional level), can also be useful for grouping, sorting, and other presentation purposes. As we shall see in the steps that follow, the .Ordinal function is again useful in helping us to meet the business need. 1. 2. Select File -- New from the main menu. Select Query with Current Connection from the cascading menu that appears next.

http://www.sqlservercentral.com/articles/MDX/72256/Printable

07/07/2011

Page 4 of 7

Illustration 4: Create a New Query with the Current Connection

A new tab, with a connection to the Adventure Works cube (we can see it listed in the selector of the Metadata pane, once again) appears in the Query pane. 3. Type (or cut and paste) the following query into the Query pane:
-- SMDX002-002 Parameter Picklist Support using .Ordinal; Display Name -for Report Parameter selector - Unique Name for passage to -Analysis Services as MDX-intelligible equivalent. WITH MEMBER [Measures].[LevelNo] AS '[Geography].[Geography].CURRENTMEMBER.LEVEL.ORDINAL' MEMBER [Measures].[DisplayName] AS '[Geography].[Geography].CURRENTMEMBER.MEMBER_CAPTION' MEMBER [Measures].[UniqueName] AS '[Geography].[Geography].CURRENTMEMBER.UNIQUENAME' SELECT {[Measures].[LevelNo], [Measures].[DisplayName], [Measures].[UniqueName]} ON AXIS(0) , {[Geography].[Geography].MEMBERS} ON AXIS(1) FROM [Adventure Works]

The Query pane appears, with our input

http://www.sqlservercentral.com/articles/MDX/72256/Printable

07/07/2011

Page 5 of 7

Illustration 5: Our Second Query in the Query Pane

4.

Execute the query by clicking the Execute button in the toolbar. The Results pane is, once again, populated by Analysis Services. This time, the dataset partially depicted appears.

Illustration 6: Results Dataset (Partial View) Report Parameter Picklist Support

In the returned dataset, we see the columns we have discussed. Of primary importance are DisplayName and UniqueName. We might certainly simply display the UniqueName to consumers for selection, as well as for insertion into our MDX query (I see this done often when a solution is developed by a practitioner new to MDX, or perhaps to components of the Microsoft integrated BI solution, particularly when they are attempting to generate the parameter support wholly within Reporting Services, etc.). Of course, more user-friendly names (hopefully those chosen for the member captions during development of the Analysis Services components) might meet with more consumer acceptance. 5. Select File -- Save MDXQuery2.mdx As location used to store the earlier query. , name the file SMDX002-002.mdx, and place it in the same

http://www.sqlservercentral.com/articles/MDX/72256/Printable

07/07/2011

Page 6 of 7

Using the .Ordinal Function as a Basis for Conditionally Displaying a Value


We will undertake an example to show how we might approach the presentation of data containing a conditional moving average, which is calculated and presented at the month level only, while the pre-existing measure is shown at all hierarchical Date levels down to month in the same results dataset. Our intent is to craft a query to generate a dataset that shows an already existing cube measure, Internet Sales Amount in one column, with a calculation, Monthly Moving Avg, (based upon a rolling six months activity) alongside it. With the levels of the Calendar Year dimension (for 2007 only, in our example) that is months, quarters, half-years and year - as the Y axis, in order to show total Internet Sales Amount for each Date dimension level, but to show the rolling average only on rows representing months, as the average is (at least to the management audience) only relevant at the monthly level. Finally, weve been told, instead of displaying a blank space or a zero within the rows where Monthly Moving Avg does not appear, we want the display to be N/A. 1. 2. Select File -- New from the main menu. Select Query with Current Connection from the cascading menu that appears next, as we did to begin the query in the last section. Another new tab again appears, with a connection to the Adventure Works cube, in the Query pane. 3. Type (or cut and paste) the following query into the Query pane:
-- SMDX002-003 Conditional management of a calculation, based upon an -existing measure and the MDX .Ordinal function WITH MEMBER [MEASURES].[Monthly Moving Avg] AS 'IIF( [Date].[Calendar].CURRENTMEMBER.LEVEL.ORDINAL = [Date].[Calendar].[Month].ORDINAL, AVG(LASTPERIODS (6, [Date].[Calendar].CURRENTMEMBER), [Measures].[Internet Sales Amount]), NULL)', FORMAT_STRING = "$#,##0;0;0;\N\\\A\" SELECT {[Measures].[Internet Sales Amount], [MEASURES].[Monthly Moving Avg]} ON AXIS (0), {DESCENDANTS([Date].[Calendar].[Calendar Year].[CY 2007], [Date].[Calendar].[Month], SELF_AND_BEFORE )} ON AXIS(1) FROM [Adventure Works]

The Query pane appears, with our input.

Illustration 7: Our Final Query in the Query Pane

http://www.sqlservercentral.com/articles/MDX/72256/Printable

07/07/2011

Page 7 of 7

4.

Execute the query by clicking the Execute button in the toolbar. The Results pane is, once again, populated by Analysis Services. The dataset appears.

Illustration 8: Results Dataset Conditional Generation and Display of Calculation

In the returned dataset, we see that the moving average appears only at the monthly levels, thanks to the comparison we perform through the use of the .Ordinal function. 5. 6. Select File -- Save MDXQuery3.mdx As , name the file SMDX002-003.mdx, and place it in the same location accessed to store the earlier query files. Select File -- Exit to leave the SQL Server Management Studio, when ready.

Summary
In this article, we explored the MDX .Ordinal function, which can be called upon in activities that range from generating simple lists and supporting parameter picklists to constructing a basis upon which we can drive conditional generation and display of calculations and other values. We introduced the function, commenting upon its operation and touching upon the creative effects we can deliver through its use. We examined the syntax involved with .Ordinal, and showed some business uses for the function by generating queries that capitalized upon its capabilities.

Copyright 2002-2011 Simple Talk Publishing. All Rights Reserved. Privacy Policy. Terms of Use. Report Abuse.

http://www.sqlservercentral.com/articles/MDX/72256/Printable

07/07/2011

Page 1 of 6

http://www.sqlservercentral.com/articles/Stairway+Series/Maintaining+cube+hierarchies/72255/
Printed 2011/07/07 08:12AM

Stairway to MDX - STEP 3: The Order() Function


By Bill_Pearson, 2011/01/24
The Order() function provides the 'hierarchized' sorts you need for reports and applications using MDX. In this Step, Business Intelligence Architect Bill Pearson explores using the versatile Order() function for providing dataset sorts that respect dimensional hierarchies.

n this session, well introduce a basic function that finds itself within expressions and queries that rank, in terms of sophistication, from the simplest to the most advanced. The Order() function provides sorting capabilities that allow us to reach beyond the natural cube structure, and is therefore an important member of our analysis and reporting toolsets.

As simple as mere ordering might appear to be, the support of hierarchies in MDX makes the processes a bit more involved. Because of the hierarchical nature of Analysis Services cubes, two general types of ordering can be found: ordering within the hierarchy ('hierarchized'), where we want to sort within the existing structure, or no ordering within the hierarchy ('non-hierarchized'), where we wish to ignore (or break) that structure. Ordering in a hierarchized manner arranges members within a given hierarchy, and then arranges the hierarchical levels. Without any explicit ordering within the hierarchy ('non-hierarchized') the arrangement of all members within the affected set ignores the hierarchy completely. In this article, we will examine the use of Order() to perform ordering within the hierarchy. (Well look at performing 'nonhierarchized') sorting in our next article.) Whether we set about meeting business analysis and reporting needs by ordering within existing hierarchies, or by ignoring those hierarchies to achieve differing orders, the general purpose of the Order() function is the same: to impose a sort order on a standard MDX set in a manner that allows us to list results based upon some criterion. The Order() function allows us to meet many common and uncommon business needs, including the obvious need to order lists of members within a set, be they employees, products, accounts, customers, months, or others; we might also wish to organize a set of members by specific attributes, such as statuses, degree of completion or readiness, and locations, to name a very few. The only difference in the use of the Order() functions to provide different types of sorts is the optional order specification at the end of the function, as we shall see. Order() can accept either a string expression or a numeric expression as criterion for ranking. Syntactically, the sort criteria and the order specification (ASC, DESC, BASC, or BDESC) are placed within the parentheses to the right of Order(), as shown in the following illustration:

Order (Set, {String Expression | Numeric Expression} [, ASC | DESC | BASC | BDESC])

The Order() function returns hierarchized data (our focus in this article) when the ASC or DESC order specifications are appended to the function, and nonhierarchized data (which we examine in The Order() Function: Beyond Cube Hierarchies)when BASC or BDESC are used. (The B serves as an instruction to break, or ignore the hierarchy.) ASC is the default order specification when none is specified in the function. In the case of the hierarchized order option, members are first ranked according to position within the hierarchy, then according to each level involved, based upon a string or numeric expression we provide. The following example expression illustrates a use of the Order() function with the hierarchized order option (inherent with the use of ASC or DESC):

ORDER( {[Product].[Product Categories].[Category].[Bikes].CHILDREN, [Product].[Product Categories].[Category].[Clothing].CHILDREN}, [Measures].[Internet Sales Amount], ASC)

This expression, contained within the row specification of a proper query (assuming the specification of the Internet Sales Amount measure in the columns axis), would result in the return of the set depicted in Table 1.
Internet Sales Amount Socks $5,106.32 Caps $19,688.10 Gloves $35,020.70 Vests $35,687.00 Shorts $71,319.81 Jerseys $172,950.68 Touring Bikes $3,844,801.05 Mountain Bikes $9,952,759.56 Road Bikes $14,520,584.04 Table 1: Ordering of the Set, Hierarchized

In the expression above, we use the Order() function to return the contents of the Bike and Clothing product categories, in Ascending (ASC) order, with respect to the total Internet Sales Amount for each. Because we use ASC (and therefore the hierarchized option), we order with respect to the existing hierarchy: We obtain the Clothing children first, sorted by Internet Sales Amount in ascending order, followed by the children of the Bikes category, sorted in ascending order. Note that, even though we specify the Bikes category before the Clothing category in the set we specify, Clothing precedes Bikes in the returned dataset. This is again because the expression we have rendered results in ordering within the existing hierarchy of the Product dimension. So we end up with an ascending sort for the children within the two categories we specify, and then a sort of those categories themselves, based upon total by Internet Sales Amount.

http://www.sqlservercentral.com/articles/Stairway+Series/Maintaining+cube+hierarch... 07/07/2011

Page 2 of 6

Ascending, by Internet Sales Amount We can order the result dataset based upon any relevant measure in just this fashion. Needless to say, proper selection, as well as filtering, of dimensions and levels is critical to prevent the MDX query from returning unexpected results.

Lets get some hands-on exposure to the basics. Well begin with a basic query, in the practice steps that follow, which does not order the data it retrieves, but returns it in its natural order. We will then have a frame of reference from which to get some practice with sorting the same data within the hierarchical structure of a representative dimension.

Using the Order() Function to Generate Hierarchized Data


Lets reinforce our understanding of the basics we have covered so far, by using the Order() function in a manner that illustrates its operation in returning hierarchized data, one of the two general, order-type options that are available, as we mentioned earlier. We will rely upon the SQL Server Management Studio (SSMS), once again, as our tool for constructing and executing the MDX we examine, and for viewing the result datasets we obtain. (If you are not sure how to set up SSMS to access the Adventure Works DW 2008R2 database, then click here for a guide.) 1. 2. 3. Start SSMS. Connect with the appropriate Analysis Server, and select the Adventure Works cube within the Adventure Works DW 2008R2 database from the Object Explorer. Click the New Query button just above the Object Explorer to open a blank Query pane, ensuring that Adventure Works appears in the Cube selector atop the Metadata pane to the right of the Object Explorer.

Natural Order within a Dimension


We will begin our exploration of the Order() function by examining how a set of data looks unordered. As we noted earlier, this will establish a frame of reference upon which we can build an understanding of how Order() can be used to sort. As many of us know, natural ordering within a given dimension of a cube is driven by the OrderBy property setting for the respective dimension attribute. It is important to keep in mind that sorting by measures is not natural, and must be accomplished via the Order() function, or by some other means, within MDX. 1. Type (or cut and paste) the following query into the Query pane:
-- SMDX003-001 Simple, unordered dataset, to demonstrate -default, "natural" sort, based upon OrderBy property -of respective attribute SELECT {[Measures].[Reseller Sales Amount]} ON AXIS(0) , {[Geography].[Geography].[Country]} ON AXIS(1) FROM [Adventure Works]

The Query pane appears, with our input.

Illustration 1: Our Initial Query in the Query Pane

2.

Execute the query by clicking the Execute button in the toolbar...

Illustration 2: Click Execute to Run the Query

The Results pane is populated by Analysis Services, and the dataset appears. In the returned dataset, we see that the data is ordered by the Country names. This natural order is enforced by the OrderBy setting within the Country dimension attribute properties, which we can examine within the Business Intelligence Development Studio, where Name is selected as shown:

http://www.sqlservercentral.com/articles/Stairway+Series/Maintaining+cube+hierarch... 07/07/2011

Page 3 of 6

Illustration 3: Results Dataset Natural Ordering

Illustration 4: OrderBy Attribute Property Setting is Name

Its easy, then, to see that the natural sort order, which is driven by an attribute property setting, has nothing to do with the measure we have specified within the column axis of our query. For that matter, as we have intimated, the only way that we can sort by a measure is through a method outside the physical dimensional structure. Order() provides the means to do this, as we shall see in our next query. 3. Select File --Save MDXQuery1.mdx As , name the file SMDX003-001, and place it in a meaningful location.

Using the Order() Function to Sort Our Data


Lets start with a simple query to gain an understanding of the use of the Order() function to return hierarchized data, or data sorted within hierarchical considerations. Our query will focus on Reseller Sales Amount, a value that is captured monthly within the Adventure Works organization, and which is stored in the Adventure Works cube. We will begin with a core query that simply pulls unsorted data, and then add Order() to achieve a desired result. 1. 2. Select File -- New from the main menu. Select Query with Current Connection from the cascading menu that appears next:

Illustration 5: Create a New Query with the Current Connection

A new tab, with a connection to the Adventure Works cube (we can see it listed in the selector of the Metadata pane, once again) appears in the Query pane. 3. Type (or cut and paste) the following query into the Query pane:
-- SMDX003-002 Simple, starter dataset, "natural" sort

http://www.sqlservercentral.com/articles/Stairway+Series/Maintaining+cube+hierarch... 07/07/2011

Page 4 of 6

SELECT {[Measures].[Reseller Sales Amount]} ON AXIS(0) , NON EMPTY {[Geography].[Geography].[State-Province].[Alabama].CHILDREN, [Geography].[Geography].[State-Province].[Alabama].CHILDREN} ON AXIS(1) FROM [Adventure Works]

The query also accomplishes a complementary objective: By selecting two separate members of the State-Province level in the Geography dimension to populate the row axis in the query, we have constructed a scenario whereby we know that we have two separate hierarchical levels; we thus have a basis for confirming the real effects of using each of the hierarchical (and nonhierarchical in our next article) sort types. The Query pane appears, with our input:

Illustration 6: Our Second Query in the Query Pane

4.

Execute the query by clicking the Execute button in the toolbar, as before. The Results pane is, once again, populated by Analysis Services. The dataset depicted appears:

Illustration 7: Results Dataset: Unordered, Retaining Natural Hierarchy

We see the total Reseller Sales Amount for each of the specified states returned. Because we have left ordering as it naturally occurs in the cube, we see the states of Alabama and Mississippi ordered by Name (ascending is the default), and, within that order, we see the cities of each state ordered by name, as well. Reseller Sales Amount is, of course, ignored. This demonstrates, once again, that hierarchical order is enforced. Lets employ Order() to work within the Geography hierarchy (State-Province level) of the cube, while ordering the returned data by the measure Reseller Sales Amount. 5. 6. 7. Select File --Save MDXQuery2.mdx As , name the file SMDX003-002, and place it in the same location used to store the earlier query. Select File --New from the main menu. Select Query with Current Connection from the cascading menu that appears next, as we did earlier. Another new tab, again connected to the Adventure Works cube, appears in the Query pane. 8. Type (or cut and paste) the following query into the Query pane:
-- SMDX003-003 Simple use of Order() function, sort descending -- (respecting hierarchies) SELECT {[Measures].[Reseller Sales Amount]} ON AXIS(0) , NON EMPTY ORDER( {[Geography].[Geography].[State-Province].[Alabama].CHILDREN, [Geography].[Geography].[State-Province].[Mississippi].CHILDREN}, [Measures].[Reseller Sales Amount], DESC ) ON AXIS(1) FROM [Adventure Works]

The query recreates the same scenario we established earlier: it generates two hierarchical levels within which we can confirm our understanding of the Order() function from a hierarchical perspective. This time, we use Order() to return the contents of the Alabama and Mississippi members of the State-Province levels of the Geography dimension, in Descending (DESC) order, with respect to the total Reseller Sales Amount for each. Because we use DESC (and therefore the hierarchized option), we order with respect to the existing hierarchy: We obtain the Mississippi children first, sorted by Reseller Sales Amount in descending order, followed by the children of Alabama, also sorted in descending order.

http://www.sqlservercentral.com/articles/Stairway+Series/Maintaining+cube+hierarch... 07/07/2011

Page 5 of 6

Note that, even though we name the Alabama state-province before the Mississippi state-province in the set we specify, we will expect Mississippi to precede Alabama in the returned dataset. This is, once again, because the rendering expressions drive ordering within the existing hierarchy of the Geography dimension. So we end up with a descending sort for the specified children (Mississippi and Alabama) within the State-Province level we specify, and then a sort of the children within each of those State-Provinces, based upon total (at each level) Reseller Sales Amount. Again, we have constructed a scenario whereby we know that we have two separate hierarchical levels; we thus have a basis for confirming the real effects of using each of the hierarchical (and nonhierarchical in our next article) sort types. The Query pane appears, with our input:

Illustration 8: Third Query: Order() Function (Descending), Respecting Hierarchies

9.

Execute the query by clicking the Execute button in the toolbar, once again. The Results pane is populated, once more, by Analysis Services, and the dataset appears.

Illustration 9: Results Dataset Order() Expression in Place, Hierarchized, Descending

As expected,the Order() function sorts our state-provinces (Alabama and Mississippi are specified in the query to populate the row axis) from highest to lowest, (and thus from Mississippi to Alabama, from the perspective of total Reseller Sales Amount), respecting state groupings in those sorts. We obtain each of the three Mississippi city-children, sorted highest to lowest, with respect to Reseller Sales Amount, followed by each of the three Alabama city-children, also sorted highest to lowest based upon Reseller Sales Amount in descending order. 10. . Select File -- Save MDXQuery3.mdx As , name the file SMDX003

Finally, lets take a quick look at how easy it is to generate the same dataset, but this time swapping the columns and rows as we have left them above, and performing our sorts across the columns. The intent here is simply to show that we can perform a columnar sort just as easily as we can do so within the rows of the dataset. 11. 12. . Select File -- New from the main menu. . Select Query with Current Connection from the cascading menu that appears next, as we did earlier. Another new tab, again connected to the Adventure Works cube, appears in the Query pane. 13. . Type (or cut and paste) the following query into the Query pane:
-- SMDX003-004 Simple Use of Order() function across columns, -- sort descending(respecting hierarchies) SELECT NON EMPTY ORDER( {[Geography].[Geography].[State-Province].[Alabama].CHILDREN, [Geography].[Geography].[State-Province].[Mississippi].CHILDREN}, [Measures].[Reseller Sales Amount], DESC ) ON AXIS(0), {[Measures].[Reseller Sales Amount]} ON AXIS(1) FROM [Adventure Works]

The query again recreates the same scenario: it generates two hierarchical levels within which we can confirm our understanding of the Order() function from a hierarchical perspective. As before, we order with respect to the existing hierarchy: We obtain the Mississippi children first, sorted by Reseller Sales Amount in descending order, followed by the children of Alabama, also sorted in descending order. Moreover, we use Order() to return the contents of the Alabama and Mississippi members of the State-Province levels of the Geography dimension, in Descending (DESC) order, with respect to the total Reseller Sales Amount for each. The difference this time is that we simply swap our column and row specifications

http://www.sqlservercentral.com/articles/Stairway+Series/Maintaining+cube+hierarch... 07/07/2011

Page 6 of 6

to demonstrate a cross-columnar sort The Query pane appears, with our input:

Illustration 10: Fourth Query: Order() Function (Descending), Respecting Hierarchies, Ordering Across Columns

14.

. Execute the query by clicking the Execute button in the toolbar, once again. The Results pane is populated, once more, by Analysis Services, and the dataset appears.

Illustration 11: Results Dataset Order() Expression in Place, Hierarchized, Descending, Ordering Across Columns

As expected,the Order() function sorts our data as before, this time ordering across columns instead of rows, with the total Reseller Sales Amount for each city appearing in the single row of the current dataset. 15. 16. . Select File -- Save MDXQuery4.mdx As , name the file SMDX004. . Select File -- Exit to leave the SQL Server Management Studio, when ready.

Summary
In this article, we explored the MDX Order() function, which is found in a range of expressions and queries from the simplest to the most advanced. We learned that Order() provides sorting capabilities that allow us to reach beyond the natural cube structure, and this function is thus an important member of our analysis and reporting toolsets. We then focused upon the use of the Order() function to return hierarchized data via the appended ASC or DESC order specifications, and looked forward to our next article, The Order() Function: Beyond Cube Hierarchies, where we expose the use of the Order() function to return nonhierarchized data when the BASC or BDESC order specifications are used. Throughout the article, we examined the syntax involved with Order(), and showed some business uses for the function by generating queries that capitalized upon its capabilities.

Copyright 2002-2011 Simple Talk Publishing. All Rights Reserved. Privacy Policy. Terms of Use. Report Abuse.

http://www.sqlservercentral.com/articles/Stairway+Series/Maintaining+cube+hierarch... 07/07/2011

Page 1 of 11

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/
Printed 2011/07/07 08:12AM

Stairway to MDX - STEP 4: The Order() Function: Beyond Cube Hierarchies


By Bill_Pearson, 2011/04/05
Use MDX to perform sorts of datasets that override the natural orders in the cube. In this lesson, Bill Pearson continues his examination of the versatile Order() function, focusing upon its use in providing dataset sorts that reach beyond dimensional hierarchies.

In the last stairway step, we introduced the Order() function, which enables us to arrange the members of a specified set, while providing us the option of preserving or breaking the existing structural hierarchy. We then explored the use of Order() in the former, simpler scenario, to arrange sets within existing hierarchies. In this article, we will get some exposure to using the function to order members of a set without regard to hierarchies. There are many times where it makes sense to ignore hierarchy completely in the arrangement of all members within a targeted set. An example might be the need to order the members of a product category that we sell by the total sales of each category, ignoring the natural sort order of the categories (say that the respective dimension design has the members ordered by name and thus in alphabetical order). As we noted in The Order() Function: Maintaining Cube Hierarchies , whether we set about meeting business analysis and reporting needs by ordering within existing hierarchies, or by ignoring those hierarchies to achieve differing orders, the general purpose of the Order() function is the same: to impose a sort order on a standard MDX set in a manner that allows us to list results based upon some criterion. The Order() function allows us to meet myriad common and uncommon business needs, including the obvious need to order lists of members within a set, be they employees, products, accounts, customers, months, or others; we might also wish to organize a set of members by specific attributes, such as statuses, degree of completion or readiness, and locations, to name a very few. The only difference in the use of the Order() functions to provide different types of sorts is the optional order specification at the end of the function, as we shall see. In case you have just joined the series with this article, lets review the basics about the Order() function, before getting into hands-on practice with the alternative use we have mentioned. As we discovered in the introductory comments of the last Step of the series , Order() can accept either a string expression or a numeric expression as criterion for ranking. Syntactically, the sort criteria and the order specification (ASC, DESC, BASC, or BDESC) are placed within the parentheses to the right of Order(), as shown in the following illustration:

Order (Set, {String Expression | Numeric Expression} [, ASC | DESC | BASC | BDESC])

The Order() function returns hierarchized data (the focus in our last step) when the ASC or DESC order specifications are appended to the function, and nonhierarchized data (which we examine in this Step of the series ) when BASC or BDESC are used. (The B serves as an instruction to break, or ignore the hierarchy.) ASC is the default order specification when none is specified in the function. In the case of the non-hierarchized order option, members are ranked based solely upon a string or numeric expression we provide, disregarding the hierarchy altogether. The following example expression illustrates a use of the Order() function with the non-hierarchized order option (inherent with the use of BASC or BDESC):

ORDER( [Date].[Calendar].[Month].MEMBERS, [Measures].[Internet Sales Amount], BASC

This expression, contained within the row specification of a proper query (assuming the specification of the Internet Sales Amount measure in the columns axis), would result in the return of the set partially depicted in Illustration 1. (The illustration shows only the portion of the dataset containing the months of 2006 and 2007.)

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 2 of 11

Illustration 1: Ordering of the Set, Non-hierarchized Ascending, by Internet Sales Amount

In the expression above, we use the Order() function to return the contents of the Month members of the Calendar user hierarchy, in Break Ascending (BASC) order, with respect to the total Internet Sales Amount for each. Because we use BASC (and therefore the non-hierarchized option), we order without respect to the existing hierarchy, based solely upon the value of the measure Internet Sales Amount, in smallest to largest order. We obtain the Internet Sales Amount for each month, sorted in ascending order. To further illuminate the effect that disregarding the hierarchy produces, lets examine the dataset that would have been returned had we used the Order() function with the ASC option that is, respecting hierarchy. Simply changing the BASC keyword to ASC in the expression above produces the results shown in Illustration 2.

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 3 of 11

Illustration 2: The Dataset Returned Using Hierarchized Ascending, by Internet Sales Amount

A close examination of the returned data will reveal that, although it appears to generally ascend, resets happen at the breakpoints of the next higher level in the Calendar user hierarchy, the Quarter level, as indicated in Illustration 3.

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 4 of 11

Illustration 3: The Dataset that Would Have Been Returned Using Hierarchized Ascending (ASC), by Internet Sales Amount

We note in our observation of the above the effects of enforcing the ascending sort, subject to the Calendar user hierarchy: The breakpoints occur based upon the Quarter level, the next highest up from the Month level. The sorting of Internet Sales Amount is taking place within the Quarter level, hence the reset with each Quarter break, as shown above. Lets get some hands-on exposure to non-hierarchized sorting with the Order() function. Well begin with a basic query, in the practice steps that follow, which orders the data it retrieves, returning it in its natural order. We will then have a frame of reference from which to get some practice with sorting the same data, disregarding the hierarchical structure of a representative dimension. We will then have a ready capability to compare the two result sets and reinforce our understanding about how sorting works when we override (or break) a user hierarchy.

Using the Order() Function to Generate Non-hierarchized Data


Lets reinforce our understanding of the basics we have covered so far, and set up a scenario whereby we can compare and contrast, by using the Order() function in a manner that illustrates its operation in returning hierarchized data. As we learned in , and as we mentioned earlier, this represents one of the two general, order-type options that are available. We will rely upon the SQL Server Management Studio (SSMS), once again, as our tool for constructing and executing the MDX we examine, as well as for viewing the result datasets we obtain. (If you are not sure how to set up SSMS to access the Adventure Works DW 2008R2 database, then click for guidance.) Start SSMS. Connect with the appropriate Analysis Server, and select the Adventure Works cube within the Adventure Works DW 2008R2 database from the Object Explorer. Click the New Query button just above the Object Explorer to open a blank Query pane, ensuring that Adventure Works appears in the Cube selector atop the Metadata pane to the right of the Object Explorer.

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 5 of 11

Beginning with a Hierarchized Sort


We will continue our exploration of the Order() function by first performing a sort by a measure, using the DESC keyword, thus keeping intact the hierarchies of two cross-joined dimensions. This will provide a framework which we can easily alter to demonstrate the differences that result from a non-hierarchized sort among identical elements. It will also offer us an opportunity to extend what weve learned about hierarchized ordering for a simple dimension / measure scenario into something a little more involved: Using Order() in hierarchized mode with multiple dimension sets. 1. Type (or cut and paste) the following query into the Query pane:
-- SMDX004-001 ORDER() Function, Sorting by Internet Sales Amount, -- DESC Keyword, Two Cross-joined Dims (Hierarchies left intact) SELECT {[Measures].[Internet Sales Amount] , [Measures].[Internet Order Quantity]} ON AXIS(0), NON EMPTY ORDER( [Product].[Category].CHILDREN * [Customer].[Country].CHILDREN, [Measures].[Internet Sales Amount], DESC) ON AXIS(1) FROM [Adventure Works]

The Query pane appears, with our input.

Illustration 4: Our Initial Query in the Query Pane

2.

Execute the query by clicking the Execute button in the toolbar... The Results pane is populated by Analysis Services, and the dataset appears.

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 6 of 11

Illustration 5: Results Dataset Hierarchized Ordering

In the returned dataset, we see that the data is ordered by the Product Category names. Within the positioning of the cross-joined Customer Country, we note that action of the hierarchized sorting is somewhat emphasized: while ordering is obviously by descending Internet Sales Amount, its easy to see that the sorts restart with each Product Category (and therefore the Customer Country children sort within the natural order of the Product Category members) , and that, while each member of the cross-joined Customer Countries is represented in each of the three sorts, these members change positions to match the ordering imposed by the Internet Sales Amount. 3. Select File -- Save MDXQuery1.mdx As location. , name the file SMDX004-001, and place it in a meaningful

To sort solely upon Internet Sales Amount, without regard to hierarchical structure as we see here, we will need to break hierarchies, as we shall see in the next section.

Ordering without Regard to Hierarchies


Lets say that, after performing the sort we examined above for a client, we are next asked to do something a bit more elaborate: we are asked by our colleagues to order the rows of the data set we have produced solely upon the measure Internet Sales Amount. They wish to see everything sorted by the measure from greatest to least value, without any of the ordering resets we saw earlier. They are therefore asking us to ignore the Product Category hierarchy altogether and to pool all Customer Countries for purposes of the sort. Lets employ Order() once again, working, as before, with the members of the Product Category and Customer Country levels of their respective dimensions, this time sorting them in truly descending order by Internet Sales Amount. 1. 2. Select File -- New from the main menu. Select Query with Current Connection from the cascading menu that appears next. A new tab, again connected to the Adventure Works cube, appears in the Query pane. 3. Type (or cut and paste) the following query into the Query pane:

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 7 of 11

-- SMDX004-002 ORDER()Function, Sorting by Internet Sales Amount, -- BDESC Keyword to break dimension / hierarchy and -- sort solely upon [Measures].[Internet Sales Amount] SELECT {[Measures].[Internet Sales Amount] , [Measures].[Internet Order Quantity]} ON AXIS(0), NON EMPTY ORDER( [Product].[Category].CHILDREN * [Customer].[Country].CHILDREN, [Measures].[Internet Sales Amount], BDESC) ON ROWS FROM [Adventure Works]

The query recreates the same scenario we established earlier: it generates two dimensions sideby-side, the examination of the behavior of whose members will allow us to confirm our understanding of the Order() function in its non-hierarchical mode. (Note that the only difference between this query and the one previous, where we ordered with respect to hierarchies, is that we use the BDESC keyword, versus the DESC keyword.) The Query pane appears, with our input:

Illustration 6: Second Query: Order() Function (Descending), Breaking Hierarchy

4.

Execute the query by clicking the Execute button in the toolbar, once again. The Results pane is populated, once more, by Analysis Services, and the dataset appears.

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 8 of 11

Illustration 7: Results Dataset Order() Expression in Place, Non-Hierarchized, Descending

As expected, the Order() function sorts our Product Category and Customer Country combinations (thus we can consider the members of each dimension on a given row pooled) from highest to lowest, from the perspective of total Internet Sales Amount, irrespective of the hierarchy of either dimension in this sort. 5. Select File -- Save MDXQuery3.mdx As , name the file SMDX004-002.

Summary Exercise: Respect Hierarchies, then Ignore Them


Finally, lets take look at another use of Order() wherein we ignore hierarchies. First, well order a data set where hierarchies are respected, the output of which we can then compare to an identical query where we break hierarchies within the sort. Our initial query / data set pair will again provide a framework which we can easily alter to demonstrate the differences that result from a non-hierarchized sort among identical elements. It will also offer us another opportunity to use Order() in hierarchized, and then non-hierarchized, modes with multiple dimension sets. 1. 2. Select File -- New from the main menu. Select Query with Current Connection from the cascading menu that appears next, as we did earlier. Another new tab, again connected to the Adventure Works cube, appears in the Query pane. First, lets perform another sort by a measure, using the DESC keyword (and thus keep intact, once again, the hierarchies of two cross-joined dimensions). 3. Type (or cut and paste) the following query into the Query pane:
-- SMDX004-003 ORDER()Function, Sorting by Reseller Sales Amount, -- DESC Keyword, Two Cross-joined Dims (respecting hierarchies) SELECT {[Measures].[Reseller Sales Amount]} ON AXIS(0), {SUBSET (ORDER ([Date].[Calendar].[Month].MEMBERS* [Product].[Product Categories].[Category].MEMBERS ,[Measures].[Reseller Sales Amount] ,DESC

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 9 of 11

) ,0 ,12 )} ON AXIS(1) FROM [Adventure Works]

The Query pane appears, with our input.

Illustration 8: Order() at Work, Again Respecting Hierarchies, in the Query Pane

4.

Execute the query by clicking the Execute button in the toolbar... The Results pane is populated by Analysis Services, and the dataset appears.

Illustration 9: Results Dataset Hierarchized Ordering

While this query is a little more elaborate than our earlier hierarchy-respecting query, we can still see similar results with regard to the sort itself. In effect, we are returning the Reseller Sales Amount for the top twelve selling categories of products, based upon the same measure. The MDX Subset() function, which we explore in an independent Stairway to MDX article, is employed to return only the first twelve tuples in the set after the result is ordered using the Order() function. In the returned dataset, we see that the data is ordered by the Calendar Month names. Within the positioning of the cross-joined Product Category, we note that action of the hierarchized sorting is

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 10 of 11

made plain, as in our earlier example: while ordering is obviously by descending Reseller Sales Amount, we can again easily ascertain that the sorts restart with each Calendar Month (and therefore the Product Category children sort within the natural order of the Calendar Month members) , and that, while each member of the cross-joined Product Categories is represented in each of the three sorts, these members change positions to match the ordering imposed by the Reseller Sales Amount. 5. Select File -- Save MDXQuery1.mdx As location. , name the file SMDX004-003, and place it in a meaningful

Next, we will see again that, to sort solely upon specified measure Reseller Sales Amount, without the regard to THE hierarchical structure we see in evidence here, we will once again need to break hierarchies, as we shall see in the next example. Well employ Order() once again, working, as before, with the members of the Calendar Month and Product Category levels of their respective dimensions, sorting them in truly descending order by the measure, Reseller Sales Amount. 6. 7. Select File -- New from the main menu, once again. Select Query with Current Connection from the cascading menu that appears next, as we did before. Another new tab, again connected to the Adventure Works cube, appears in the Query pane. 8. Type (or cut and paste) the following query into the Query pane:
-- SMDX004-004 ORDER()Function, Sorting by Reseller Sales Amount, -- BDESC Keyword, Two Cross-joined Dims (ignoring hierarchies) SELECT {[Measures].[Reseller Sales Amount]} ON AXIS(0), {SUBSET (ORDER ([Date].[Calendar].[Month].MEMBERS* [Product].[Product Categories].[Category].MEMBERS ,[Measures].[Reseller Sales Amount] ,BDESC ) ,0 ,12 )} ON AXIS(1) FROM [Adventure Works]

Note that the query is identical to the query we created in our last example, except for one small difference: the DESC keyword of the last query (which dictated that the Order() function respect hierarchies) has now become BDESC. Moreover, the query recreates the same scenario we established earlier: it generates two dimensions side-by-side, the examination of the behavior of whose members will allow us to confirm our understanding of the Order() function, only this time in its non-hierarchical mode. The Query pane appears, with our input:

Illustration 10: Order() Function (Descending), Once Again Breaking Hierarchy

9.

Execute the query by clicking the Execute button in the toolbar, once again. The Results pane is populated, once more, by Analysis Services, and the dataset appears.

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 11 of 11

Illustration 11: Results Dataset Order() Expression in Place, Non-Hierarchized, Descending

As expected, the Order() function sorts our Calendar Month and Product Category combinations (as if they were pooled, once again, from highest to lowest, from the perspective of total Reseller Sales Amount, completely without regard to the hierarchy of either dimension in this sort. (The Subset() function, once again, serves to deliver the Reseller Sales Amount for the top twelve selling categories of products, based upon the same measure.) 10. 11. Select File -- Save MDXQuery3.mdx As , naming the file SMDX004-004. Select File -- Exit to leave the SQL Server Management Studio, when ready.

Summary
In this article, we further explored the MDX Order() function, which, as we noted in The Order() Function: Maintaining Cube Hierarchies, finds itself within expressions and queries that rank from the simplest to the most advanced. We learned, in general, that Order() provides sorting capabilities that allow us to reach beyond the natural cube structure, and this function is thus an important member of our analysis and reporting toolsets. We then expanded beyond what we had learned in The Order() Function: Maintaining Cube Hierarchies , and focused upon the use of the Order() function to return non-hierarchized data via the appended BASC or BDESC order specifications, comparing the results we obtained in each of a couple of practice exercises to a those of identical queries, in each case, that respected hierarchies. Throughout the article, we examined the syntax involved with Order(), and showed some business uses for the function by generating queries that capitalized upon its capabilities.

Copyright 2002-2011 Simple Talk Publishing. All Rights Reserved. Privacy Policy. Terms of Use. Report Abuse.

http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable

07/07/2011

Page 1 of 6

http://www.sqlservercentral.com/articles/Stairway+Series/Membes+and+Member+functions+in+MDX/73786/
Printed 2011/07/07 08:17AM

Stairway to MDX - STEP 5: Members, and an Introduction to the MDX Members Functions
By Bill_Pearson, 2011/05/19
In this Step, I will introduce the concept of members, within the context of Analysis Services. Well preview the member functions as a general group (to be explored individually in later steps), and then look specifically at the .Members function, within MDX. Well focus on the composition and nature of these important components of the language, and obtain hands-on exposure to their use in simple expressions that we will run to view their output. Ill emphasize rules of syntax as we move along: the knowledge we gradually build of these rules will provide a basis for progressively more sophisticated query building as we continue through the Stairway to MDX series. Lets begin by discussing members in general, and by performing an overview of member functions as a group.

Members and the Member Functions


As many of us are aware, members represent an important and pervasive concept within a practical understanding of MDX. A member is, simply, an item in a dimension; members compose the values of the attributes that belong to a dimension. (Keep in mind that measures are themselves members of a dimension - the measures dimension). To illustrate, for a dimension based upon geography, which might contain Country, State and City as levels, USA, Idaho, and New Orleans might represent, respectively, valid members. MDX contains a set of functions, known as member functions, each of which enables us to perform operations upon any member of a dimension. Member functions return a member or members, where they exist. A simple illustration that follows our geography example above would be as follows: The .Parent function, applied to the member New Orleans - as in New Orleans.Parent would equal Louisiana. As well discover, member functions allow us to perform operations, based upon a members relative position, either up (above the member upon which the function is being performed) or down (below the member upon which the function is being performed) a dimensional hierarchy. Well see numerous examples of this in the coming Member Functions discussions, in this and other Steps of the series, that focus upon family member functions. For now, lets look at the details surrounding the .Members function.

The .Members Function


The .Members function provides a ready means of obtaining the membership for a given level, hierarchy or dimension (unless the dimension under consideration contains more than one hierarchy, in which case a hierarchy must be explicitly specified). The importance of the .Members function becomes clear when we get enough exposure to MDX under our belts to realize that this is a very common point from which we conduct more involved operations. A simple illustration of the .Members function in action follows:
SELECT [Measures].MEMBERS ON COLUMNS, [Product].[Product Categories].MEMBERS ON FROM [Adventure Works]

ROWS

Heres a partial view of the result dataset:

Illustration 1: Example Result Dataset (Partial View) from Using the .MEMBERS Function As we can see, the .Members function produces a result dataset containing:

http://www.sqlservercentral.com/articles/Stairway+Series/Membes+and+Member+fu...

07/07/2011

Page 2 of 6

All members of the Measures dimension (as columns); All members of the Product dimension Product Categories hierarchy (as rows). It is important to remember that the .Members function must be applied at a level within a dimension where hierarchy (and thus the membership we are requesting) is not ambiguous. If multiple hierarchies exist within a dimension, we must apply the .Members function at or below the level of the split, in a manner of speaking; that is, if we attempt an operation similar to that which we performed above, and multiple hierarchies exist within the dimension selected (this can occur in a Time / Date dimension, for example, where fiscal and calendar hierarchies often share the same dimension), the membership we are requesting is not precise, and our attempt will end with an error. Lets examine the syntax. The .Members function is appended to the right of the level, hierarchy or dimension, as in the following illustration (from the earlier example):
[Product].[Product Categories].MEMBERS

It might also have been appended in the same manner to enumerate the members of the Categorylevel within the same Productdimension Product Categories hierarchy, as in the following example:
[Product].[Product Categories].[Category].MEMBERS

Well illustrate the use of the .Members function at various levels in the Practice section that follows. NOTE: While we have yet to introduce Calculated Members to any real extent within the series, it is important to be aware that Calculated Members will not appear in the result dataset returned by the .Members function. As well discover in later Steps of the Stairway to MDX series, the .AllMembers function, among other means, exist to include Calculated Members in our result datasets. Lets get some hands-on practice with the .Members function, keeping an eye on the results we get with each query we construct. We will be working with the MDX Query Editor in SSMS. If you are not sure how to set up SSMS in Analysis Services to access the Adventure Works DW 2008R2 database, then click here for guidance. For purposes of our practice session, lets assume that we have been given a business requirement by a hypothetical client. We are asked by an information consumer in the Sales and Marketing department of the Adventure Works organization to provide the total Internet Order Quantity, together with Internet Sales Amount, for each of the various Product Categories sold by the organization, over Calendar Year 2008. We are asked, moreover, to provide the information in a two-dimensional grid, with the measures (Internet Order Quantity and Internet Sales Amount) in the column headings and all products (the full membership of Product Category) on the rows. Type (or copy and paste) the following query into the Query pane:
-SMDX005-001: Basic Use of .MEMBERS

SELECT { [Measures].[Internet Order Quantity], [Measures].[Internet Sales Amount] } ON AXIS(0), { [Product].[Product Categories].[Category].MEMBERS FROM [Adventure Works] WHERE ([Date].[Calendar Year].[CY 2008])

} ON AXIS(1)

The Query pane appears, with our input.

Illustration 2: The Query in the Query Pane Select Query on the top menu, and then select Execute (!).

http://www.sqlservercentral.com/articles/Stairway+Series/Membes+and+Member+fu...

07/07/2011

Page 3 of 6

Illustration 3: Executing the Query from the Main Menu... We see the results appear in the Query pane as soon as Analysis Services fills the cells that it determines to be specified by the query.

Illustration 4: The Initial Query Results NOTE: For an explanation of the comment line, together with other general discussion surrounding attributes of the basic MDX query structure, see my charter article, Stairway to MDX - STEP 1: Getting Started with MDX. The query delivers the results that were requested by the information consumer. Select File -- Save MDXQuery1.mdx As , name the file SMDX005-001, and place it in a meaningful location. Now lets delve a bit deeper, and undertake an exercise to illustrate the use of the .Members function in varying levels of the same hierarchy. This time, lets say that we are asked by the Adventure Works Sales and Marketing department to provide the total Reseller Order Quantity, together with total Reseller Sales Amount, for the organization, over the years of operation represented by our cube. The ultimate use for the information, they say, will be to support a simple drilldown report, but, for the time being, the consumers want to understand how to break down the values for all members of the Calendar hierarchy of the Date dimension. Select File --> New from the top menu. Select Query with Current Connection from the cascading menu that appears next. Type (or copy and paste) the following query into the Query pane:
-SMDX005-002: Another Basic Use of .MEMBERS

SELECT { [Measures].[Reseller Order Quantity], [Measures].[Reseller Sales Amount] } ON AXIS(0), { [Date].[Calendar].MEMBERS } ON AXIS(1) FROM [Adventure Works] The query appears within the Query pane.

Illustration 5: The Query in the Query Pane Click the Execute (!) button in the toolbar atop the Management Studio. The Results pane appears as partially shown.

http://www.sqlservercentral.com/articles/Stairway+Series/Membes+and+Member+fu...

07/07/2011

Page 4 of 6

Illustration 6: The Query Results Dataset (Partial View) The results dataset contains many empty members, intermingled with populated members, as we can see by scrolling down. Empty cells occur in MDX statements when data for the intersection of multiple dimensions (in our example, the intersection of the Reseller Order Quantity and the Reseller Sales Amount, measures, and the Date dimension) does not exist. To make our points with the .Members function a bit clearer to see, lets issue instructions in our query to eliminate the empties, by adding the NON EMPTY keyword as follows: Type in the NON EMPTY keyword just before the following line of the query above:
{ [Date].[Calendar].MEMBERS } ON ROWS

The query appears, with the added keyword circled, in the Query pane as depicted here.

Illustration 7: The Query Pane with the Added NON EMPTY Keyword (Circled) Were using the NON EMPTY keyword simply to issue instructions to Analysis Services: exclude Date dimension (Calendar hierarchy) members in the rows where totals for Reseller Order Quantity and Reseller Sales Amount do not exist. The empty tuples will thereby be screened out of the results dataset of the MDX query. Click the Execute (!) button in the toolbar atop the Management Studio, once again. The new Results pane appears, as partially shown.

Illustration 8: The Query Results (Partial View) Empties Removed Save the query by selecting File --> Save MDXQuery2.mdx As , naming the file SMDX005-002.mdx, and placing it in a convenient location. Now, to continue with the focus of our lesson, the .Members function, we can see in the example we have created that the use

http://www.sqlservercentral.com/articles/Stairway+Series/Membes+and+Member+fu...

07/07/2011

Page 5 of 6

of .Members in the above query gives us every member of the Date dimension Calendar hierarchy, including levels and the members for each of those levels. This result might tend to confuse more than help an information consumer, because total numbers would not necessarily agree with a total of the values appearing in the results dataset for either measure. In short, a dump of the entire list of hierarchy objects with their associated values might not serve to be useful from an analysis perspective to an uninformed consumer. Lets explore going to a specific level in the Calendar hierarchy for the Date dimension. Select File --> New from the top menu, once again. Select Query with Current Connection from the cascading menu that appears next, as we did earlier. Type (or copy and paste) the following query into the Query pane:
-SMDX005-003: Using .MEMBERS at a Hierarchy Level

SELECT { [Measures].[Reseller Order Quantity], [Measures].[Reseller Sales Amount] } ON NON EMPTY { [Date].[Calendar].[Calendar FROM [Adventure Works]

AXIS(0), Year].MEMBERS } ON AXIS(1)

The query appears within the Query pane.

Illustration 9: The Query in the Query Pane We are now using the .Member function to ask for the membership of the Calendar Year level (of the Date dimension Calendar hierarchy) in the row axis. Click the Execute (!) button in the toolbar, once again. The Results pane appears.

Illustration 10: The Query Results Members of the Calendar Year Level Appear We see that we have now obtained a summary, by Calendar Year, of the two measures and by Calendar Year only because we made the more specific request for members of the Calendar Year level. Save the query as SMDX005-001.mdx. We can easily replicate the effects we have obtained at the Calendar Semester, Calendar Quarter, and other levels of the Date dimension and its associated hierarchies, as well as in the other dimensions and their levels. As we progress into the multi-article Member Functionssegment of our series, and the coverage of many of the member functions available in MDX, as well as into even more advanced stages of query building, we will revisit the .Members function often. Practice with this powerful function will make its use easy and natural; we will come to value it highly in the more advanced MDX exercises we undertake in later Steps. Select File -- Exit to leave the SQL Server Management Studio, when ready.

Summary
In this Step, we introduced the concept of members in Analysis Services, and then moved into an exploration of the .Members function, as well as setting the scene for the examination of the general member functions that we will undertake in the next Steps of the series. We focused upon the composition of these important components of the MDX language in general, and provided handson exposure to the .Members function in simple expressions we crafted together, and for each of which we discussed the results

http://www.sqlservercentral.com/articles/Stairway+Series/Membes+and+Member+fu...

07/07/2011

Page 6 of 6

delivered. I emphasized throughout the Step the importance of understanding the member concepts and the use of the member functions. A thorough grasp of these important MDX components is essential for developing increasingly more sophisticated queries as we continue through the Stairway to MDX series. Copyright 2002-2011 Simple Talk Publishing. All Rights Reserved. Privacy Policy. Terms of Use. Report Abuse.

http://www.sqlservercentral.com/articles/Stairway+Series/Membes+and+Member+fu...

07/07/2011

Page 1 of 11

http://www.sqlservercentral.com/articles/Stairway+Series/73789/
Printed 2011/07/07 08:18AM

Stairway to MDX - STEP 6: Member Family Functions: .Parent and .Children


By Bill_Pearson, 2011/05/19
In this Step, we will continue the introduction to the general MDX member functions I began in Step 5: Members, and an Introduction to the MDX Members Functions. In gaining our first exposure to the member functions, we will take some time to begin to get to know the family. I began calling one specific subset of the member functions the family functions in MDX articles I published in the 2003 2004 timeframe, because many of their names resemble those of family members. (This naming of the group has been widely adopted since.) Some of the functions that comprise the family functions group include: .Parent .Children Ancestor() Cousin() .FirstChild .LastChild .FirstSibling .LastSibling As Ive stated often since then, the family metaphor is appropriate, because these functions perform operations on dimensions, hierarchies and levels in a manner that mirrors movement about a family tree. There are other family functions that return sets, too, of course, but I will focus primarily on the respective member functions over the next few steps of our series. I will discuss some of the concepts that underlie the family functions, and expose the appropriate syntax involved in using each effectively. For each function, we will then get some hands-on exposure to its use in simple expressions / queries that we will, in turn, execute against the sample Analysis Services database to view the output and reinforce our understanding of the function / component from the perspective of the results dataset that it returns. This Step will also include further general discussion surrounding members, and member functions and their roles in MDX, when relevant to the component under consideration. Ill also introduce the WHERE clause, and give some details on the general specification of slicers within an MDX query. Finally, we will look ahead, throughout this Step, to the additional member family functions that we will explore in forthcoming Steps. Lets begin with an overview of the family member functions as a group.

Introducing the Family Member Functions


As a part of my introduction to the concept of members in Analysis Services in Step 5: Members, and an Introduction to the MDX Members Functions, where I introduced the highly useful .Members function for starters, I launched an examination of the MDX member functions that will span multiple Steps of this series. This and subsequent Steps will focus upon a few member functions at a

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 2 of 11

time, beginning with the family functions, contrasting the uses and effects of each. In this Step, I will expose the .Parent and .Children member functions, discussing the information they return, together with syntactical points of their use. We will gain the know-how needed to take advantage of these useful functions through the typical Stairway practice exercises, whereby we construct queries that use the functions, and then examine together the results datasets those queries deliver. Ive learned, after years of working with the language, and from the comments of many of my readers, that this is a great way to learn MDX. The family functions, like other member functions, belong to two general groups, from the perspective of the result datasets they return. One group works within a vertical scope, traveling up or down between hierarchical levels, as we will see in the respective practice section for each function. Examples include the following functions: Ancestor() .Children .Parent .FirstChild .LastChild. The second general group of family functions operates within a horizontal scope of the hierarchy involved. These functions travel within the same level of the hierarchy (across versus up and down), and include: .Cousin() .FirstSibling .LastSibling The capability to perform operations within the vertical and horizontal scopes of the hierarchy can mean more efficient, simpler MDX queries queries that effectively leverage multidimensional structures created to make information rapidly available for analysis and reporting. Well take a look at the family functions individually to obtain a good understanding of their workings in the sections devoted to each that follow.

The .Parent Function


As were about to see, the .Parent function returns the parent of a specified member using the syntax that follows. (The function is especially useful in calculated members, with which we will work heavily later in the series.) The .Parent function is appended to the right of the member, as in the following illustration:
<member>.Parent

A simple illustration of the .Parent function in action follows:


SELECT NON EMPTY {[Date].[Calendar].[Calendar Year].MEMBERS} ON COLUMNS, {[Product].[Category].[Bikes].PARENT} ON ROWS FROM [Adventure Works] WHERE ([Measures].[Internet Sales Amount])

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 3 of 11

The results dataset returned when executing the above would appear as depicted here.

Illustration 1: Example Result Dataset from Using the .Parent Function Perhaps a look at the hierarchy for Bikes, the source - or child - member from the perspective of the .Parent function above, will make the illustration more meaningful. From a browse of the cube, and specifically the Product dimension, we can see that Bikes is a child of the All Products level, within the Category attributehierarchy of the Product dimension.

Illustration 2: The Attribute Hierarchy Containing the All Products Level, Parent to the Bikes Member In this simple example we can also see that the parent member is All Products. We will likely more deeply appreciate the significance of the .Parent function at a later point, when we are not applying the function to a specific source member, but are using a relative member, such as .CurrentMember, where the calculation within which we find it determines its context. (More on this will come later). As I have already mentioned in a previous Step, and as many readers will already know, the WHERE clause is optional in a query, and determines the member or dimension to be used as the slicer. This specification limits the data returned to specific dimension(s) or member(s). The example I have cited here uses a WHERE clause to limit the data extracted for the axis dimensions to a specific member of the Measures dimension, Internet Sales Amount. This represents a simple WHERE clause: our use of the WHERE clause will take many forms as we progress through the Stairway to MDXseries, and we will address more elaborate uses as they arise. Lets reinforce our understanding of how the .Parent function operates by constructing an expression that calls it into action. Well use the same core expression, starting with an expression that does not

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 4 of 11

use the function (and to which we will add it later) throughout the lesson, which will allow us to explore the different results we obtain in a way that the respective returned data sets can be contrasted against one another. We will, as usual, work with the MDX Query Editor in SSMS. If you are not sure how to set up SSMS to access the Adventure Works DW 2008R2 Analysis Services database, then click here for guidance. To get started, lets assume that we have, once again, been given a business requirement by a hypothetical client: We have been asked by an analyst in the Sales and Marketing department of the Adventure Works organization to provide the total Internet Order Quantity for a specific subcategory of products, Mountain Bikes, sold by the organization over the Calendar Years whose data is contained in the Adventure Works cube. In this case, we are asked to provide the information in a two-dimensional grid, once again, with the Calendar Years in the column axis (or Axis (0) ), and the specified product subcategory member of interest, the Mountain Bikes Product subcategory in the row axis ( Axis (1) ). Type (or copy and paste) the following query into a blank Query pane:
-SMDX006-001: Using .MEMBERS in Initial -- Demonstration Query to Prep for .PARENT

SELECT NON EMPTY {[Date].[Calendar].[Calendar Year].MEMBERS} ON AXIS(0), {[Product].[Product Categories].[Subcategory].[Mountain Bikes]} ON AXIS(1) FROM [Adventure Works] WHERE ([Measures].[Internet Order Quantity])

The query appears within the Query pane.

Illustration 3: The Query in the Query Pane Click the Execute (!) button in the toolbar, once again. The Results pane is populated with the dataset.

Illustration 4: The Query Results Preliminary Core Query Results Dataset We see that we have obtained a summary, by Calendar Year (having once again applied the .Members function to the Calendar Year level of the Date dimension Calendar hierarchy), of

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 5 of 11

Internet Order Quantity sold for the Mountain Bikes product subcategory. Save the query by selecting File --> Save MDXQuery1.mdx As , naming the file SMDX006-001, and placing it in a meaningful location. Now lets extend our basic query to illustrate the operation of the .Parent function. A quick look at the hierarchy illustrates the relationships between the members and levels under consideration.

Illustration 5: The Hierarchy under Consideration Type (or copy and paste) the following query into the Query pane:
-SMDX006-002: Using .PARENT Function in Row Specification

SELECT NON EMPTY {[Date].[Calendar].[Calendar {[Product].[Product ON AXIS(1) FROM [Adventure Works] WHERE ([Measures].[Internet Order Quantity])

Year].MEMBERS} ON AXIS(0),

Categories].[Subcategory].[Mountain Bikes].PARENT}

The query appears within the Query pane.

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 6 of 11

Illustration 6: The Modified Query in the Query Pane Click the Execute (!) button in the toolbar, as before. The Results pane is populated.

Illustration 7: The Query Results Extended Query Example The results dataset displays the totals at the Bikes level, which is somewhat obviously the Parent of the Mountain Bikes member (the source member upon which the .Parent function is enacted in our query above). We see that we have now obtained a summary at the Bikes level of the Internet Order Quantity for the calendar years 2005 through 2008, because we affixed the .Parent function to the Mountain Bikes level. As we have stated before, we will find the .Parent function far more powerful at a later juncture in our series, when we are using a relative member, such as .CurrentMember, where the calculation within which .Parent is placed will determine its context. Save the query by selecting File --> Save MDXQuery2.mdx As , and naming the file SMDX006-002. Now that weve seen how to use the .Parent function, lets move to the next family member function, .Children.

The .Children Function


Much like the .Parent function, the .Children function works within a vertical scope, moving down between hierarchical levels from the source member to which the function is applied. As its name implies, the .Children function returns the children of the source member. Again resembling the .Parent function (except for the direction of its travel), the .Children function is especially useful in calculated members, among other scenarios, most of which we will explore later in the Stairway to MDX series. Syntactically, the .Children function is appended to the right of the member:
<member>.Children

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 7 of 11

A simple illustration of the .Children function, using an example somewhat similar to the example I cited earlier to illustrate the syntax for the .Parent function, is as follows:
SELECT NON EMPTY {[Date].[Calendar].[Calendar Year].MEMBERS} ON COLUMNS, {[Product].[Product Categories].[Category].[Bikes].CHILDREN} ON ROWS FROM [Adventure Works] WHERE ([Measures].[Internet Sales Amount])

The results dataset returned when executing the above would appear as shown:

Illustration 8: Example Results Dataset Generated Using the .Children Function Referring again to the hierarchical structure within which our source member lies, we can see that the .Children function has caused a shift in the opposite direction to that we saw for the .Parent function above.

Illustration 9: Downward Movement along the Hierarchy under Consideration We can begin the reinforcement of our understanding of how the .Children function operates by working within another simple illustration, and extending that illustration to other basic examples that actually add the .Children function to a given member. To get started, lets assume that we have, as before, been given a business requirement by a hypothetical client: We have been, once again,

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 8 of 11

asked by an analyst in the Sales and Marketing department of the Adventure Works organization to provide the total Internet Order Quantity for all children (the individual bike products) of the specific subcategory of products, Mountain Bikes, sold by the organization, over the Calendar Years whose data is contained in the Adventure Works cube. Once again, we are asked to provide the information in a two-dimensional grid, with the Calendar Years in the column axis and the specified product members of interest, the various individual Mountain Bikes, in the row axis. Select File --> New from the top menu. Select Query with Current Connection from the cascading menu that appears next, once again. Type (or copy and paste) the following query into the Query pane:
-SMDX006-003: Using .CHILDREN Function in Row Specification

SELECT NON EMPTY {[Date].[Calendar].[Calendar Year].MEMBERS} ON AXIS(0), {[Product].[Product Categories].[Subcategory].[Mountain Bikes].CHILDREN} ON AXIS(1) FROM [Adventure Works] WHERE ([Measures].[Internet Order Quantity])

The query appears within the Query pane.

Illustration 10: The Query in the Query Pane Click the Execute (!) button in the toolbar, as before. The Results pane is populated as partially depicted here.

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 9 of 11

Illustration 11: The Query Results in the Results Pane (Partial View) The results dataset displays the totals at the level of the individual bikes, the Children of the Mountain Bikes member (the source member upon which the .Children function is enacted in our query above). We have now obtained a summary of Internet Order Quantity for each constituent member of Mountain Bikes for the calendar years 2005 through 2008, because we affixed the .Children function to the Mountain Bikes level. As we have stated to be the case with other functions we have examined in this article, we will find the .Children function far more powerful at a later juncture in our series, when we are using a relative member, such as .CurrentMember, so that the calculation within which .Children is placed determines its context. Save the query by selecting File --> Save MDXQuery6.mdx As , and naming the file SMDX006-001.mdx. Now, to reinforce understanding, lets illustrate the operation of the .Children function once again, with another example. Select File --> New from the top menu. Select Query with Current Connection from the cascading menu that appears next, once again. Type (or copy and paste) the following query into the Query pane:
--SMDX006-004: Using .CHILDREN Function in Second Example Row Specification,

SELECT NON EMPTY {[Date].[Calendar].[Calendar Year].MEMBERS} ON AXIS(0), NON EMPTY { [Product].[Product Model Lines].[Product Line].[Accessory].CHILDREN} ON AXIS(1) FROM [Adventure Works] WHERE ([Measures].[Internet Order Quantity], [Customer].[Customer Geography].[Country].[United Kingdom])

In addition to using the .Children function with another source member, we are also expanding the

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 10 of 11

WHERE statement (see above for a discussion) to expand, in turn, the slicer dimension to specify not only the Internet Order Quantity measure, but a single customer Country, the United Kingdom. The cube is therefore filtered, or sliced for the Internet Order Quantity and the United Kingdom members, within the context in which they are specified. The query appears within the Query pane.

Illustration 12: The Query in the Query Pane Click the Execute (!) button in the toolbar, as before. Analysis Services populates the Results pane, once again.

Illustration 13: The Query Results in the Results Pane (Partial View) The results dataset displays the Internet Order Quantity totals for the children of the Product Accessory level, for the calendar years 2007 and 2008, as purchased by customers in the United Kingdom. Save the query by selecting File --> Save MDXQuery7.mdx As , and naming the file

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

Page 11 of 11

SMDX006-001.mdx. Exit SQL Server Management Studio as desired. As we move into subsequent Steps of Stairway to MDX, and into the use of many of the functions available in MDX, as well as into progressively more advanced stages of query building, we will call upon these and other family functions frequently. As well see, they are often quite powerful when used in tandem with other functions. As we have noted throughout the series so far, a grasp of the basic operators and functions will be vital to success in our taking advantage of the more complex MDX concepts that we will uncover as we proceed. Practice with these components will assure that their use comes as second nature to us, and will create a foundation from which the power and elegance of MDX can be fully exploited.

Summary
In this Step, we continued the introduction to the general MDX member functions I began in Step 5: Members, and an Introduction to the MDX Members Functions, where I also introduced the pervasive and powerful .Members function. In gaining our first exposure to the member functions, we began an examination that will span several Steps of this series, with each Step focusing upon a couple of member functions at a time. In this Step, we got some hands-on familiarity with the .Parent and .Children member functions, discussing the syntax within which they are used, as well as the information they return and other details. We again gained the know-how needed to take advantage of these useful functions through the typical Stairway practice exercises, whereby we constructed queries that used each function, and then examined together the results datasets those queries delivered. Copyright 2002-2011 Simple Talk Publishing. All Rights Reserved. Privacy Policy. Terms of Use. Report Abuse.

http://www.sqlservercentral.com/articles/Stairway+Series/73789/Printable

07/07/2011

You might also like