MDX Essentials - MDX Time Series Functions, Part III: The LastPeriods() and ParallelPeriod() Functions

Monday Sep 8th 2003 by William Pearson
Share:

Join author Bill Pearson in the last of three articles surrounding the time series functions, designed to support the analysis of data within the context of time. In this lesson, we will explore the LastPeriods() and ParallelPeriod() function.

About the Series ...

This is the eleventh article of the series, MDX Essentials. The primary focus of this series is an introduction to MDX. The series is designed to provide hands-on application of the fundamentals of the Multidimensional Expressions (MDX) language, with each tutorial progressively adding features designed to meet specific real-world needs.

For more information about the series in general, as well as the software and systems requirements for getting the most out of the lessons included, please see the first article, MDX at First Glance: Introduction to MDX Essentials.

Note: Service Pack 3 updates are assumed for MSSQL Server 2000, MSSQL Server 2000 Analysis Services, and the related Books Online and Samples.

What We Accomplished in our Last Article

In the tenth article of the series, MDX Time Series Functions, Part II: The OpeningPeriod() and ClosingPeriod() Functions, we continued our introduction to the time series functions group, noting that MDX provides this specialized group of functions to perform analysis within the context of time. After discussing the common business need to analyze data over time, and, more specific to our lesson, within a scope of the opening or closing periods of a given time window, we examined the OpeningPeriod() and ClosingPeriod () functions in detail. In the case of each, we illustrated the syntax that is appropriate for its effective use, and then tested our understanding of how to leverage the function by undertaking a relevant practice exercise.

As has been the case with numerous functions in past lessons, we revisited the construction of a calculated member, building a calculated measure within our practice queries as a vehicle for illustrating the operation of the OpeningPeriod() and ClosingPeriod () functions. Finally, we discussed the results that each practice example obtained, comparing the results of the ClosingPeriod () function with the OpeningPeriod() function to emphasize their similarity in construction and operation.

In this lesson, we will introduce two remaining time series functions, LastPeriods() and ParallelPeriod(). Like the other members of this specialized functions group, these functions support the common business requirement to produce results in reference to time; another characteristic that they have in common with the rest of the time series functions is that, while they are typically used with time-type dimensions, they can be applied to non-time dimensions, too.

Introduction

In our introductory comments in MDX Time Series Functions, Part I: PeriodsToDate() and Kindred Functions, we discussed the fact that most of us have become acquainted with the need to perform data analysis from the perspective of time. We mentioned that examples abound, including business requirements to analyze growth (for instance in revenues or expenses) over periods in time (say, between the years 1997 and 1998). We also touched upon other examples, such as the presentation of year-to-date totals, averages or other accumulations. We noted that the primary mission of the time functions is to navigate within the time dimension, thus supporting our analytical needs within a time context.

We learned that the time series functions can be applied to non-time dimensions, but that, by and large, they are specifically designed to support time-based analysis. These functions stand ready to enable us to easily navigate within the time dimension, as we pointed out, to such places as "this month last year," "the first month in the quarter," or "our current point in the year, last year."

Along with an introduction to the LastPeriods() and ParallelPeriod() functions, this lesson will include:

  • an examination of the syntax surrounding the use of each function;
  • an illustrative example of the use of each function in a practice exercise;
  • a brief discussion of the MDX results we obtain in each practice example.

The LastPeriods() Function

The LastPeriods() function, according to the Analysis Services Books Online, "returns a set of members prior to and including a specified member." Almost as simple as it sounds, the function returns (in its typical use within the context of a time dimension) the set of periods beginning with the period that follows (or lags) the specified member by a specified index value, less one, up to and including the specified member. (If the member is not specified in the function, Time.CurrentMember is defaulted.) Indeed, LastPeriods() resembles PeriodsToDate()(explored in MDX Time Series Functions, Part I: PeriodsToDate() and Kindred Functions), which returns all of the members back to the beginning of a specified period, although the LastPeriods() function returns the number of members that is specified by an index value.

The index (minus one) that is specified tells the function how far to "look back" for purposes of the returned dataset. If the index is positive, the function returns the set of members whose range is headed up by the member "lagging" one less than the index value from the specified member, and that ends with the member itself. If the index is negative, then LastPeriods() returns the set of members that begins with the specified member itself, and ends with the member leading (or "ahead in time") by the negative index value, minus one, from the specified member. Finally, an empty set is returned if the index value is zero.

Discussion

The LastPeriods() function allows us to meet numerous common business needs, including (and especially) those that require that we return (individually or for accumulation) values from, for example, "several periods back," up to, and including, the specified period. That specified member might be, for example, a specific quarter for which we would like monthly values over the range of, say, two quarters back through the current quarter. A calculation can be driven for a several month's activities, as another example, whose range is determined by the beginning and ending points that result from the index we provide.

As we discussed in our last lesson, balances are maintained up to the current point in time / held at various points in time for many accounts whose activity we might wish to analyze, such as Sales, Inventory, Purchases, and various other accounts that contain values besides dollar amounts, such as shares outstanding, headcount, various quantities, and so forth, in our systems. The values most likely to be of interest in typical uses of the LastPeriods() function would most likely relate to deltas over the given periods. Ss an illustration, the total sales over each of a given group of months (itself the delta of "ending total sales" between the point in time that we establish as the specified member within the function, and the total sales value that existed, in this example, at the earlier point in the year to which we are looking back, and which is index - 1 months back). LastPeriods() is excellent for the derivation of "total activity for the last (whatever number) periods back," and, thus for a "to date" cumulative total of sorts. Utilitarian beauty appears, again, in the use of the function with .currentmember, etc. to gain a context sensitive calculation that can flex automatically as time marches on. Running averages and other derivatives of the accumulated totals are obvious easy byproducts, as well, given formulation within an expression that includes LastPeriods().

Common examples of scenarios where LastPeriods() might come in handy include monthly totals / balances, over a few quarters, for the inventories of a group of products we manufacture and sell, for perhaps comparison to the same amounts for another group of our products, as an aid in determining whether to discontinue production of a given item or items to allow us to compose a more rapidly moving product mix. Another illustration might lie in the need to analyze activity, particularly over several summer months, in total monthly quantity on hand, for a part that we stock in a Repair Parts account for use in maintaining our air conditioning plant, to ascertain, perhaps, increased demands for parts by an aging system.

MDX provides an excellent means for accumulating these time-ranged activity values over specified time frames. The LastPeriods() function affords us a ready means to navigate to the first member of the range for which one endpoint (the specified member) is defined and for which the opposite end of the range is specified by the index.

Let's look at an illustration to further clarify the operation of LastPeriods().

Syntax

Syntactically, the index and the specified member are placed within the parentheses to the right of LastPeriods(), as shown in the following illustration:

	LastPeriods(<<Index>>[, <<Member>>])

The function returns the set of members prior to (by <<Index>> - 1 "member-places"), and including, <<Member>>. The following simple example expression:

	LastPeriods (11, [Time].[1998].[Q3].[8])

would return the following set of month-members:

	{[Time].[1997].[Q4].[10],
	  [Time].[1997].[Q4].[11],
	  [Time].[1997].[Q4].[12]
	  [Time].[1998].[Q1].[1]
	  [Time].[1998].[Q1].[2]
	  [Time].[1998].[Q1].[3]
	  [Time].[1998].[Q2].[4]
	  [Time].[1998].[Q2].[5]
	  [Time].[1998].[Q2].[6]
	  [Time].[1998].[Q3].[7]
	  [Time].[1998].[Q3].[8]}
  

Practice

Let's reinforce our understanding of the basics we have covered so far, by using the LastPeriods() function in a manner that illustrates its operation. The MDX Sample Application (see the second article in our series, Structure of the MDX Data Model, for more information about the Sample Application) will, again, be our tool for constructing and executing the MDX we examine, and for viewing the result datasets we obtain.

1.  Start the MDX Sample Application.

2.  Clear the top area (the Query pane) of any queries or remnants that might appear.

3.  Ensure that FoodMart 2000 is selected as the database name in the DB box of the toolbar.

4.  Select the Warehouse cube in the Cube drop-down list box.

We will compose a simple query to gain an understanding of our data; our query will focus on the Warehouse Cost measure, a value that is captured monthly within the FoodMart organization and which is stored in the Warehouse cube.

5.  Type the following query into the Query pane:

-- MDX11-1:  Tutorial
Query No. 1
SELECT    
  
{[Measures].[Warehouse Cost]} ON COLUMNS,    
    LastPeriods(11,
[Time].[1998].[Q3].[8]) ON ROWS
FROM Warehouse

6.  Click the Run button on the toolbar atop the Sample Application, to execute the query.

Analysis Services fills the Results pane, presenting the dataset depicted in Illustration 1.


Illustration 1: Result Dataset - LastPeriods() Function

We see the total organization Warehouse Cost returned for each of the last eleven periods (our index of 11 in the query), within the range of periods that ends at August (Quarter 3), 1998, and begins ten (index of eleven minus one) months back at October (Quarter 4), 1997. As we learned in the Syntax section above, the result dataset is equivalent to

	{[Time].[1997].[Q4].[10],
	  [Time].[1997].[Q4].[11],
	  [Time].[1997].[Q4].[12]
	  [Time].[1998].[Q1].[1]
	  [Time].[1998].[Q1].[2]
	  [Time].[1998].[Q1].[3]
	  [Time].[1998].[Q2].[4]
	  [Time].[1998].[Q2].[5]
	  [Time].[1998].[Q2].[6]
	  [Time].[1998].[Q3].[7]
	  [Time].[1998].[Q3].[8]}
  

We can easily prove that the two are equivalent by taking the following steps:

7.  Type the following query into the Query pane:

-- MDX11-1 Proof:  Proof of Query No. 1
SELECT
	{[Measures].[Warehouse Cost]} ON COLUMNS,    
    	{[Time].[1997].[Q4].[10],
			[Time].[1997].[Q4].[11],
	    [Time].[1997].[Q4].[12],
	    [Time].[1998].[Q1].[1],
	    [Time].[1998].[Q1].[2],
	    [Time].[1998].[Q1].[3],
	    [Time].[1998].[Q2].[4],
	    [Time].[1998].[Q2].[5],
	    [Time].[1998].[Q2].[6],
	    [Time].[1998].[Q3].[7],
	    [Time].[1998].[Q3].[8]}
                    	ON ROWS
FROM Warehouse

8.  Click the Run button on the toolbar atop the Sample Application, to execute the query.

As soon as the specified cells in the Results pane are filled by Analysis Services, we see the result dataset depicted in Illustration 2.


Illustration 2: The Query Result Dataset

The proof query delivers the results that we expected, based upon our discussion of the syntax of the LastPeriods() function: We see that the results are identical to those we obtained in the previous query, within which we used the more compact LastPeriods() function.

If it is desirable to save this or subsequent queries, we can do so by selecting File -> Save As, and give the file a meaningful name and location.

Now let's take a look at our remaining time series function, ParallelPeriod().

The ParallelPeriod() Function

The ParallelPeriod() function, according to the Analysis Services Books Online, "returns a member from a prior period in the same relative position as a specified member." This function would serve, as an illustration, to make it easy for us to navigate to "our current point in the year, last year," be the current point a month, quarter, or other period supported by our cube structure.

Similar to the case of the Cousin() function (see the seventh article in this series, Member Functions: The Cousin () Function), the ParallelPeriod() function operates upon the order and position of members within levels; ParallelPeriod() returns the child member with the same relative position under a given parent member as the specified child member under its own parent. The ParallelPeriod() function is more specifically adapted to time dimensions than Cousin(). It takes the ancestor of the specified member (in the typical case, a period), at a specified level, then looks at the specified sibling of the ancestor (who lags by a specified numeric expression) and returns the parallel period of the specified member from the descendants of that sibling.

When a level is not specified, the default member is Time.CurrentMember. When a level is specified, the default member is Dimension.CurrentMember, where Dimension is the dimension within which the specified level is a member. The default level is the parent of the specified member. The "lag distance" specified in the numeric expression defaults to "1," when it is not specified.

Discussion

The ParallelPeriod() function allows us to meet a business need that is common to virtually all industries. It allows us to return, for a given period, a value for its parallel in another time frame. ParallelPeriod() allows us to compare, for example, the sales over a given month with the sales that took place over the same month in the prior year, or a for a quarter this year over the same quarter last year. This might be particularly useful in a business whose revenues are highly seasonal (as in the case of a retail organization for whom Q4 - a large portion of which is Christmas shopping season - might make more sense to compare to Q4 of the prior year, rather than to Q3 of this year, when sales might have been (unsurprisingly) less.

As is the case with most of the time series functions, other, less direct approaches exist to meet business requirements of this nature. But ParallelPeriod() provides an easy, time-focused approach to this common need, as we will see in the sections that follow.

Syntax

Syntactically, the level, the sibling lag expression, and the specified member is placed within the parentheses to the right of ParallelPeriod(), as shown in the following illustration:

ParallelPeriod([<<Level>>[, <<Numeric Expression>>[, <<Member>>]]])

ParallelPeriod() takes the ancestor of <<Member>> at <<Level>> in the first argument, then returns the period parallel to <<Member>> under the ancestor's sibling that lags by <<Numeric Expression>>. The following simple example expression:

 ParallelPeriod ([Quarter], 2,[1998].[Q3].[9])

navigates to the sibling of the quarter-level ancestor of Quarter 3 (Q3 in the FoodMart sample cubes) in 1998, moves two quarters back (to Quarter 1), and then returns the cousin of September, (Month "9" in the FoodMart cubes) 1998. The month that is returned is therefore March (Month "3" in the FoodMart cubes).

Practice

Let's confirm our understanding of the function under consideration by using the ParallelPeriod() function in a way that we can get a feel for its operation.

We will create a simple query, which will again focus on Warehouse Cost.

1.  Type the following query into the Query pane:

-- MDX11-2:  Tutorial Query No. 2
SELECT
  
{[Measures].[Warehouse Cost]} ON COLUMNS,    
     { ParallelPeriod ([Quarter], 2,[1998].[Q3].[9])}ON ROWS
FROM Warehouse

Analysis Services fills the Results pane, presenting the dataset depicted in Illustration 3.


Illustration 3: Result Dataset - ParallelPeriod() Function

We see the total Warehouse Cost returned for Month 3 of Quarter 1 of 1998. As we discovered above, Quarter 1 is two quarters back from Quarter 3, which is the value of the numeric expression / index in the ParallelPeriod() function that we have used. Once we navigate to Quarter 1, the parallel month to Month 9 in Quarter 3 (the "last of the three months" in the quarter) is Month 3 (also the "last of the three months of the quarter").

We can prove the accuracy in the use of the ParallelPeriods() function by first reasoning that the "cousin" month for September (the third month in its quarter) in any given year is as follows for each of the other quarters of the year:

Quarter 1

March

Quarter 2

June

Quarter 4

December

Table 1: "Cousins" - The Third Month in Each Quarter

We realize that we wish to navigate to two quarters back in the timeline, so we know that we wish to focus on Quarter 1. Reasoning tells us that March, 1998, is therefore our targeted time dimension member.

Next, we can simply query the cube for the Warehouse Cost value for March 1998, by taking the following steps:

2.  Type the following query into the Query pane:

-- MDX11-2 Proof: Tutorial Query No. 2 Proof
SELECT    
  
{[Measures].[Warehouse Cost]} ON COLUMNS,    
    { [Time].[1998].[Q1].[3]} ON ROWS
FROM Warehouse

3.  Click the Run button on the toolbar atop the Sample Application, to execute the query.

Analysis Services does its work, resulting in the result dataset shown in Illustration 4.


Illustration 4: The Proof Query Result Dataset

The proof query delivers the results that we expected, based upon an alternative approach to the ParallelPeriods() function that we ran initially: The same results are generated from a more direct request for the value at the "parallel" month that the function should have, and apparently did, insert for us in the previous query.

In conclusion, we can easily see the utility of the LastPeriods() and ParallelPeriod () functions in providing us a relative route to data that is typically most useful within the context of time - utility that we can fine-tune with parameters that we can specify within arguments provided to the function.

Summary...

In this lesson, we concluded our examination of several useful members of the time series functions group, with two additional time-related functions, LastPeriods() and ParallelPeriod(). After discussing further the general business need to analyze data over time, we first overviewed the LastPeriods() and ParallelPeriod() functions. For each function, we then illustrated the syntax that is appropriate for its effective use. Finally, we tested our understanding of how to leverage the function by undertaking a relevant practice exercise, discussing the results we obtained and performing additional proof exercises to confirm their accuracy.

» See All Articles by Columnist William E. Pearson, III

Discuss this article in the MSSQL Server 2000 Analysis Services and MDX Topics Forum.

Share:
Home
Mobile Site | Full Site
Copyright 2017 © QuinStreet Inc. All Rights Reserved