Professional Documents
Culture Documents
http://www.sqlservercentral.com/articles/Stairway+Series/71867/
Printed 2011/07/07 08:08AM
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...
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.
http://www.sqlservercentral.com/articles/Stairway+Series/71867/Printable
07/07/2011
Page 3 of 13
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.
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
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
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.
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.
We will be using the Query pane to construct and execute MDX queries throughout the practice sessions of this series.
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.
[ 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.
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.
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.
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.
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:
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.
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.
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.
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.
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.
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
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
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 ...
...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:
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.
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 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...
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
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
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]
http://www.sqlservercentral.com/articles/MDX/72256/Printable
07/07/2011
Page 5 of 7
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.
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
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.
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
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):
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.
2.
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
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.
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:
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:
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:
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.
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
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):
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
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.
http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable
07/07/2011
Page 5 of 11
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
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.
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:
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
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.
http://www.sqlservercentral.com/articles/Beyond+Cube+Hierarchies/72884/Printable
07/07/2011
Page 9 of 11
4.
Execute the query by clicking the Execute button in the toolbar... The Results pane is populated by Analysis Services, and the dataset appears.
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:
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
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.
ROWS
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)
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]
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
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.
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])
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}
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.
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])
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