Home > Articles > Data > SQL Server

Like this article? We recommend

Creating Calculated Members

We left the previous article with a preview of building calculated members, in which we undertook the creation of a simple dynamic calculated member. Our knowledge of sets at this stage prepared us to begin a discussion of calculated members in general, and we created a basic dynamic calculated member to conclude our introduction to MDX queries, while demonstrating yet another capability of this powerful OLAP reporting language.

A Return to Dynamic Calculated Members

As discussed earlier, MDX allows us to perform calculations on ranges of cells, leveraging our programming efforts over those of programs that require us to implant them at the cell level. We can place calculations in our query axes, making them new members of the dimensions involved. The cells that appear within these members present the query results. Within the realm of MDX, calculated members can be created a couple of main ways.

The first method of creation, using the WITH operator, will be the focus of the first sections of our lesson. The WITH operator in an MDX query creates a dynamic calculated member; that is, the member, and therefore the calculation that the member performs, exists only during the runtime life of the query. The second means of creating a calculated member is through the use of the CREATE MEMBER statement. Calculated members that are born this way are "permanent" and can be made visible to all clients that can access the cube in which the calculated member is housed. Non-query-defined calculated members are beyond the scope of our current lesson.

Our first exercise will be to create a basic dynamic calculated member in an MDX query. We will then build upon our knowledge to add more capabilities while discussing potential uses for our calculated members. We will begin by firing up the MDX sample application once again because it provides an excellent platform from which to learn about MDX:

  1. Go to the Start button on the PC; navigate to Microsoft SQL Server, Analysis Services; then navigate to the MDX Sample Application.

    The Connect dialog box appears (see Figure 1).

    Figure 1Figure 1 The Connect dialog box for the MDX sample application.

    Figure 1 depicts the name of my server, MOTHER, and properly indicates that we will be connecting via the MSOLAP provider (the default).

  2. Click OK.

    NOTE

    We might also choose to cancel the dialog box and connect later by clicking Connect on the File menu.

    The MDX Sample Application window appears.

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

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

  5. Select the HR cube in the Cube drop-down list box.

The MDX Sample Application window should resemble that shown in Figure 2, complete with the information from the HR cube displaying in the Metadata tree (the left section of the Metadata pane).

Figure 2Figure 2 MDX Sample Application window.

Many similarities exist between the arrangements of objects in the Metadata pane and the Calculated Member Builder. We will discuss various attributes of the MDX sample application when they are relevant to the exercises we undertake, but it is highly useful to explore the Books Online for a wealth of detail about the application.

To begin our examination of calculated members, we will create a simple Average Salary member:

  1. Type the following query into the Query pane:

    SELECT
    [Measures].Members ON COLUMNS,
    [Employees].Members ON ROWS 
    FROM [HR]
  2. Click the Run Query button (the button sporting the green arrowhead-shaped icon.

  3. A tooltip will alight when the cursor is placed upon the button to positively identify it.

The rather lengthy results set are partially shown in Figure 3.

Figure 3Figure 3 Initial results set from the HR cube.

Our query has returned the three measures it found in the HR cube as column headings:

  • Org Salary
  • Count
  • Number of Employees

The WITH operator can be used in MDX queries to define our calculated members, among other uses. WITH precedes the SELECT clause in the statement, stipulating a section in which the calculated member (together with named sets) is defined in the query. Let's take a look at placement and use of the WITH operator, which will allow us to return data and calculations in a straightforward manner.

In our example, we will create a calculated member, which we will call Average Salary, to show a simple salary average for the employees/groups of employees that are returned in our result set. Note that the Average Salary calculation is defined as a member as a result of using the WITH statement (hence the name "calculated member").

  1. Insert the following into the Query pane, into the existing query before the SELECT clause:

    WITH
    MEMBER [Measures].[Average Salary] AS
    '[Org Salary]/[Number of Employees]'

    The query should now resemble that shown in the Query pane shown in Figure 4.

    Figure 4Figure 4 The initial query; WITH clause added to create a calculated member.

  2. Click the Run Query button.

    The results set appears, but it is identical to the last (refer to Figure 3).

Our query returns the new result set—and nothing has changed since before the addition of the WITH statement. The .Members portion of the column axis we have defined does not include calculated members. To cause calculated members to appear, we need to insert the AllMembers function.

  1. Adjust the query, substituting the AllMembers function, as shown in Figure 5.

    Figure 5Figure 5 The modified query—adding the AllMembers function.

  2. Click the Run Query button.

    The results set appears—this time revealing the new calculated member Average Salary, as shown in Figure 6.

    Figure 6Figure 6 The calculated member appears—twice!

But what is happening here? We have two calculated members that appear to calculate the same Average Salary figure. The first calculated member, Avg Salary, is a calculated member that was defined at the cube level, built into the sample as an illustration of the mechanics behind doing so. We find this out because the AllMembers function results in the display of all calculated members as well as standard members; and in our case, we happen to have created a calculation that is identical (except for formatting) to the non-query defined calculated member that already existed in the cube structure.

This serves as a good illustration of the advisability of familiarizing ourselves with the structure of a cube before adding calculated members. In this case, it also gives us a quick check to see that our calculation is performing as expected, delivering the correct average salary amount (sans formatting, once again). We will leave things as they are because the calculated member that already existed is permanent, but our new Average Salary member, dynamically defined by the query, exists only with the execution of the query.

  1. Add a comment to the query, as shown in Figure 7, for easy identification at a later time (after we run the query, the comment tag will appear in the Queries selector list at the top-right side of the toolbar in the sample application, making it easier to find).

    Figure 7Figure 7 Add a comment for easy identification in the Queries selector list.

  2. Save the query file, naming it CM_AvgSal for easy identification, as a calculated member sample.

We need only use the Member clause, preceded by the WITH keyword, for each calculated member we wish to add. We will practice this again, with variations, as we advance through this lesson and in later lessons.

Let's get started with an exercise that will gradually build into a multifaceted query that illustrates multiple perspectives of working with calculated members. Let's say, for purposes of illustration, that a group of information consumers has asked us to assist with building a query to show the percent change in the profits of the current quarter (we'll imagine we are in the second quarter of 1997) over the quarter before. The query will rely upon several concepts that we will discuss as we progress.

First, we'll return to the sample application and begin afresh.

  1. Click the New Query button to start a new query.

  2. Select the Warehouse and Sales cube, as shown in Figure 8.

    Figure 8Figure 8 Select the Warehouse and Sales cube.

  3. Type the following basic query, complete with the comment line, into the Query pane:

    --Step1
    SELECT 
      {[Time].[1997].[Q1],
      [Time].[1997].[Q2]} ON COLUMNS,
    { [Measures].[Store Sales],
      [Measures].[Store Cost]} ON ROWS
    FROM [Warehouse and Sales]

Our intent here is to set up the basis for further exploration. The --Step 1 comment indicates the step of our build, and we'll repeat this process at each step, saving each before continuing so as to have a "fallback" position, in case we get off-track and need to return to the "last known good configuration." This has saved me many hours in lost re-creation time when just such a thing has occurred, particularly if I am building logic on-the-fly, and experimenting with each step to achieve a specific result.

The query we typed above makes use of sets, indicated by braces ( { } ), to build the column and row axes.

  1. Execute the query by clicking the Run Query button.

    The result set appears in Figure 9.

    Figure 9Figure 9 Step 1 results.

The basics of calculating profit have been retrieved: Even a non-accountant knows that Store Sales and Store Cost will allow us to derive Store Profit, which has not yet been defined, as a calculated member in the Warehouse and Sales cube. Once we have the Store Profit, our next step is to compute the percent change in profit between Quarter 2 (Q2) and Quarter 1 (Q1) of 1997.

  1. Save the query as Step1, leaving it open for the next step.

  2. Type the following statement into the Query pane before the SELECT clause, replacing the top comment line with --Step 2.

    WITH 
      MEMBER [Measures].[Store Profit] AS 
      '[Measures].[Store Sales] - [Measures].[Store Cost]'
    
  3. After the [Measures].[Store Cost] portion of the SELECT clause (and within the braces), add a comma and then the following line below it, just before the close brace (}) and ON ROWS:

      [Measures].[Store Profit]  

The complete modified query should appear in the Query pane, as shown in Figure 10.

Figure 10Figure 10 Step 2, as it appears in the Query pane (additions circled).

The addition we have made in the form of the WITH clause creates a calculated member called Store Profit, and the addition of the newly defined calculated member in the set below instructs the application to return it as an additional row in our result set, bringing us one step closer to meeting the requirements of the information consumers that we described above.

  1. Execute the query by clicking the Run Query button.

    The result set appears in Figure 11.

    Figure 11Figure 11 Step 2 results.

We will handle the formatting later. The important thing at present is that we appear to have achieved the desired result, and have derived and displayed the needed Store Profit amounts with our new calculated member. Let's now add calculation of the next part of the requirement, Percentage Change, to our query.

  1. Save the query with changes as Step2.

  2. Modify the comment line to read --Step3.

  3. Insert the following statement into the Query pane, within the WITH clause, between the [Measures].[Store Cost] portion (do not place a comma after [Measures].[Store Cost]), added in query Step2 and the SELECT clause, replacing the top comment line with --Step 3.

      MEMBER [Time].[% Change] AS 
         '([Time].[1997].[Q2]-[Time].[1997].[Q1])/[Time].[1997].[Q1]'
  4. After the [Time].[1997].[Q2] portion of the SELECT clause and within the braces, add a comma; then add the following line below it, just before the close brace (}) and ON COLUMNS:

    [Time].[% Change]
      

The complete modified query should appear in the Query pane, as shown in Figure 12.

Figure 12Figure 12 Step 3 as it appears in the Query pane.

The addition we have made in the form of the WITH clause creates a calculated member called % Change, and the addition of the newly defined calculated member in the set below instructs the application to return it as an additional column in our result set.

  1. Execute the query by clicking the Run Query button.

    The result set appears in Figure 13.

    Figure 13Figure 13 Step 3 results.

As we see above, formatting aside, we approach even more closely the objectives of the information consumers. We now have a column that presents the % Change calculation based upon the first calculated member, which derived the delta value between the quarters.

  1. Save the query with changes as Step3, again leaving it open for the next steps.

I make it a practice to save formatting for last when creating queries, writing reports, or anything related to the derivation and subsequent presentation of information because much rework can be saved by avoiding the inevitable changes associated with adding to or modifying a report. Although I may find it hard to resist the urge to "go ahead and clear up the picture," years of experience have made it clear that this is a key kind of discipline to have, especially with elaborate queries and complex reporting.

In direct contradiction to this principle, however, I have found that although carrying out the highly efficient process of presenting a draft of the report/result sets to many information consumers, the appearance of the data often outweighs the content itself. Many of us have experienced the manager/staff member who wants, in effect, to remake the new information product in the likeness of an existing report.

While existing reports can be effective guides to creating new reports, the direct replication approach can be taken too far. I cannot count the times I have been asked to produce reports that must "resemble exactly" their mainframe counterparts—even being asked a couple of times if I could create reports to resemble green bar completely! The issue with this is often one of common sense: the mainframe report presented things in the way it did because it had to. Limitations in the environment dictated very rigid report layouts—layouts that are neither required nor even sensible with the analysis and reporting tools we have today. What's more, to design a report to mirror the outmoded workings of the previous system often means hamstringing the processing speeds and other characteristics of our more evolved packages. Scores of examples exist in "typical" financial reports produced by the standard systems of old.

While my initial reaction to the "identical replication" approach is to attempt to reason with the manager in terms he/she can understand, this appeal to logic is sometimes unsuccessful. Suffice it to say that the client ultimately gets what they want, sometimes to the detriment of the information consumers, and with the effect of handicapping the organization's competitiveness. For the occasional organizations that take this route, there certainly will be competitors who are more interested in the accurate and optimal delivery and presentation of data, and who will take advantage of the powerful features that are available in applications such as Analysis Services.

My point here is that there are certainly ways to format and arrange layouts to resemble almost any model that is preferred. The important thing is to realize that if the selection and/or derivation of the data is optimized from the ground up, with "form following substance," and the formats are being added thoughtfully and globally after data selection considerations have been met, performance of the information product will likely be enhanced.

That being said, let's take a look at some formatting techniques. We can begin by making the % Change cells more compact for ease of use in the design.

  1. Insert the following just ahead of the ([Time].[1997].[Q2]-[Time].[1997].[Q1])/[Time].[1997].[Q1]' part of the WITH clause (last line of the clause):

    '100 *
  2. Change the comment line to read --Step 4.

    The modified query should appear in the Query pane, as shown in Figure 14.

    Figure 14Figure 14 Step 4, as it appears in the Query pane, with addition circled.

  3. Execute the query.

    The result set appears in Figure 15.

    Figure 15Figure 15 Step 4 results.

We see the % Change column for the first two rows more closely resembles a percent figure to which most of us can relate, with the currency symbol in front of the top field of the column being a matter for later resolution. This was easily accomplished by the simple addition of the multiplier—one of numerous ways (and not necessarily the most optimal in a production setting) to accomplish the same task.

But the number that appears in the last row of this column, formed by the % Change/Store Profit calculated members' intersection, brings to light a consideration that is somewhat weightier than mere formatting concerns.

  1. Save the query with changes as Step4, leaving it open for the next steps.

Specifying Precedence of Calculation

We have created two calculated members at this stage, Store Profit and % Change, to meet the demands of the information consumers we have referenced. We placed the % Change member on the column axis (similar to the x-axis, for the multidimensionally challenged), and made it a column in our result set. We made the Store Profit member a row (the y-axis equivalent) axis member through our query design. Our focus at this stage is the behavior of the corner cell that results: Depending on the order in which the two calculations are processed, the result in the corner cell is different.

We can easily assume that what the consumers want here is a result that represents the change in overall Store Profit between Q1 and Q2. The number that we see is apparently not correct from that perspective. This brings us to another implicit requirement for our information product: We need to be able to dictate, in this and similar situations, which calculation takes precedence in the design of our query.

MDX provides a solution in the form of the Member Solve Order property. The solve order is specified when the member is created, and thus becomes a feature of the WITH clause we have constructed. Member Solve Order is designated through the assignment of a number, which dictates that the member(s) with the higher assigned number(s) be processed after the member(s) with the lower number(s), based upon the results of the preceding calculation(s). The number is defaulted to zero if no positive integer value is specified. We can thus control the precedence of calculation of the members, as we will see.

To restate our objective within this step, we need to derive and present the change in Store Profit between Q2 and Q1, not to present an amount based upon the difference in the Store Sales and Store Cost delta values. We thus want the Store Profit member to be calculated first, or to have precedence, and the % Change member to be calculated thereafter. We accomplish our objective by taking the following steps:

  1. Modify the comment line to read --Step 5.

  2. After the '[Measures].[Store Sales] - [Measures].[Store Cost]' portion of the WITH clause, add a comma and then add the following line below it, just above the MEMBER [Time].[% Change] AS line:

    SOLVE_ORDER = 1
  3. After the '100 * ([Time].[1997].[Q2]-[Time].[1997].[Q1])/[Time].[1997].[Q1]' portion of the WITH clause, add a comma and then add the following line below it, just above the SELECT keyword:

    SOLVE_ORDER = 2

    The modified query should appear, in its entirety, in the Query pane, as shown in Figure 16.

    Figure 16Figure 16 Step 5 with modifications noted, as it appears in the Query pane.

  4. Execute the query.

    The result set appears in Figure 17.

    Figure 17Figure 17 Step 5 results.

    The result matches our expectation, and substantially meets the requirements of the information consumers.

  5. Save the query with changes as Step5, leaving it open for the next steps.

We have now completed the derivation of the desired information and set up the layout for its presentation through our query design. Provided that no further calculations or other design criteria are imposed, this might be a good time to clean up our formats with a further enhancement. We will put in place some formatting instructions, which are typically added in the same area of the WITH clause (where the calculated members and their attributes are defined), just behind the MEMBER SOLVE ORDER property values, as we will see in the next steps.

  1. Modify the comment line to read --Step 6.

  2. Remove the '100 * that we inserted just ahead of the ([Time].[1997].[Q2]-[Time].[1997].[Q1])/[Time].[1997].[Q1]' part of the WITH clause (in Step4).

  3. Insert a comma, followed by the text below, after the SOLVE ORDER = 1 member property instruction for the Store Profit calculated member we created in the WITH clause of the query:

    FORMAT_STRING = '#,##0.00;(#,##0.00)'
  4. Insert a comma, followed by the text below, after the SOLVE ORDER = 2 member property instruction for the % Change calculated member we created in the WITH clause of the query:

    FORMAT_STRING = 'Percent'

    The modified query should appear in its entirety in the Query pane, as shown in Figure 18.

    Figure 18Figure 18 Step 6, with modifications circled, as it appears in the Query pane.

  5. Execute the query.

    The result set appears in Figure 19.

    Figure 19Figure 19 Step 6 results.

The result matches our expectation, and helps us to substantially meet the requirements of the information consumers. The recovering CPA in me tends to be accustomed to the amount at the top of a column being preceded by the dollar sign, but we could have added dollar signs to each of the amounts—there are many options available.

  1. Save the query with changes as Step6.

Using the WITH clause, we have created the two calculated members that deliver the desired information specified by the information consumers. Inside the WITH clause lies the MEMBER clause that actually does the work for us (we can also create Named Sets). The MEMBER clause allows us to create multiple calculated members, as we have seen.

Throughout our lesson, we have focused on the most common form of calculated member that we can expect to encounter in the business environment: the calculated measure (a member of the measures dimension). We will resume our exploration of calculated members in our next article, "Building Calculated Members, Part 2," with the creation of a calculated member of a standard dimension, and work through some exercises to see why this is useful.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020