Creating OLAP DML Formulas Using AWM Templates

One of the most powerful features of the multidimensional engine behind analytic workspaces is the ability to create formulas. Formulas, or "calculated measures" as they're referred to in AWM10g, are measures that are derived from other measures. Using AWM, you can create simple formulas that reference other measures in a cube, allowing you for example to create a "margin" measure derived from sales and costs measures. If you're an old Express hand though, you'll know that this simple type of formulas is just the tip of the iceberg, and what you often used to end up doing was creating for example a three dimensional formula based on measures from four and five dimensional variables, rolling up unneeded dimensions and pulling in variables held in what would now be referred to as "cubes".

To take an example, say that you had a table of branches:

SQL> select * from branches;

BRANCH_ID BRANCH_DESC REGION_ID REGION_DESC TOTAL_BRANCHES_ID TOTAL_BRANCHES_


     1 Brighton                10 South-East                    100 All Branches
     2 Worthing                10 South-East                    100 All Branches
     3 Charing Cross           11 London                        100 All Branches
     4 Liverpool               12 North-West                    100 All Branches
     5 Manchester              12 North-West                    100 All Branches</pre>

and a table of accounts:

SQL> select * from accounts;

ACCOUNT_ID ACCOUNT_DESC TOTAL_ACCOUNTS_ID TOTAL_ACCOUNTS_


     1 Wages                         100 All Accounts
     2 Sales                         100 All Accounts</pre>

and then a table of account balances:

SQL> select * from balances;

ACCOUNT_ID BRANCH_ID BALANCE


     1          1         50
     2          1         80
     1          2         40
     2          2         40
     1          3        100
     2          3        125
     1          4         80
     2          4         60
     1          5         90
     2          5         95

10 rows selected.

We then create an analytic workspace with account and branch dimensions, and a balances cube:

Once the analytic workspace has been loaded from our source tables, we can open up the OLAP Worksheet and take a look at what's been created.

-> listnames
   39 DIMENSIONs                      52 VARIABLEs
   --------------------------------   --------------------------------
   ACCOUNTS                           ACCOUNTS_ACCOUNT_H_HIERDEF
   ACCOUNTS_HIERLIST                  ACCOUNTS_ACCOUNT_LEVELDEF
   ACCOUNTS_LEVELLIST                 ACCOUNTS_COLUMN_COUNT
   AGGREGATE_DIMENSION_PROP           ACCOUNTS_COLUMN_MAP
   AGGREGATE_GENERIC_PROP             ACCOUNTS_CREATEDBY
   ALLOCATE_DIMENSION_PROP            ACCOUNTS_HIER_IS_VALUE
   ALLOCATE_GENERIC_PROP              ACCOUNTS_IS_SESSION
   ALL_ATTRIBUTES                     ACCOUNTS_LONG_DESCRIPTION
   ALL_ATTRTYPES                      ACCOUNTS_SHORT_DESCRIPTION
   ALL_CALC_MEMBERS                   ACCOUNTS_TOTAL_ACCOUNTS_LEVELDEF
   ALL_CUBES                          AGGREGATE_DIMENSION_CATALOG
   ALL_DESCTYPES                      AGGREGATE_GENERIC_CATALOG
   ALL_DIMENSIONS                     ALLOCATE_DIMENSION_CATALOG
   ALL_HIERARCHIES                    ALLOCATE_GENERIC_CATALOG
   ALL_LANGUAGES                      ALL_DESCRIPTIONS
   ALL_LEVELS                         ALL_TOOLS_PROP
   ALL_MEASUREFOLDERS                 ATTR_DATA_MAP
   ALL_MEASURES                       ATTR_VISIBLE
   ALL_MODELS                         AW_NAMES
   ALL_OBJECTS                        BALANCES_BALANCE_COUNTVAR
   ALL_SOLVEDFNS                      BALANCES_BALANCE_STORED
   ALL_SOLVEGROUPS                    BRANCHES_BRANCHES_H_HIERDEF
   ALL_SOLVES                         BRANCHES_BRANCH_LEVELDEF
   BALANCES                           BRANCHES_COLUMN_COUNT
   BRANCHES                           BRANCHES_COLUMN_MAP
   BRANCHES_HIERLIST                  BRANCHES_CREATEDBY
   BRANCHES_LEVELLIST                 BRANCHES_HIER_IS_VALUE
   CALC_MEMBER_PROP                   BRANCHES_IS_SESSION
   COLUMN_DIM                         BRANCHES_LONG_DESCRIPTION
   CUBE_PROP                          BRANCHES_REGION_LEVELDEF
   DIM_OBJ_LIST                       BRANCHES_SHORT_DESCRIPTION
   FORECAST_PROP                      BRANCHES_TOTAL_BRANCHES_LEVELDEF
   GEN_OBJ_ROLES                      CALC_MEMBER_CATALOG
   GID_DIMENSION                      CUBE_CATALOG
   IS_LOADED_DIMENSION                DIMKEY_IS_UNIQUE
   MAPGROUP_DIM                       DIM_AW_OBJS
   MEASURE_PROP                       DIM_KEY_MAP
   TIME_GLEVEL_DIMENSION              FORECAST_CATALOG
   TIME_OFFSET_DIMENSION              GEN_AW_OBJS
                                      MEASURE_CATALOG
                                      MEAS_DATA_MAP
                                      MEAS_KEY_MAP
                                      MEAS_OPERATOR_MAP
                                      OBJECT_LOADED
                                      OBJ_CREATEDBY
                                      OBJ_ORIGINATOR
                                      PARENT_KEY_MAP
                                      PARENT_LVL_MAP
                                      SOLVEDFN_TYPE
                                      SOLVE_MEMBER_SELECTION
                                      VISIBLE
                                      ___XML_USER_AW_VERSION

1 PROGRAM 1 FORMULA


ONATTACH BALANCES_BALANCE

37 RELATIONs 5 COMPOSITEs


ACCOUNTS_FAMILYREL ATTR_MAP_COMPOSITE
ACCOUNTS_FAMILYRELVAL BALANCES_COMPOSITE
ACCOUNTS_GID HIERLVL_MAP_COMPOSITE
ACCOUNTS_LEVELREL LVL_MAP_COMPOSITE
ACCOUNTS_LOADED MEAS_MAP_COMPOSITE
ACCOUNTS_PARENTREL
BRANCHES_FAMILYREL
BRANCHES_FAMILYRELVAL
BRANCHES_GID
BRANCHES_LEVELREL
BRANCHES_LOADED
BRANCHES_PARENTREL
CALC_MEMBER_BASE_DIMENSION
CUBE_AGGREGATION
CUBE_DFLT_PARTITION_HIERARCHY
CUBE_DFLT_PARTITION_LEVEL
CUBE_MEASURES
DEFAULT_HIER
DIM_ATTRIBUTES
DIM_HIERARCHIES
DIM_LEVELS
DYNAMIC_MEAS_AGGREGATION
FOLDER_PARENTREL
HIER_SORT_ATTR
MAPGROUP_CUBEREL
MAPGROUP_DIMREL
MAPGROUP_HIERREL
MAPGROUP_LVLREL
MEAS_DOMAIN
MEAS_PARTITION_HIERARCHY
MEAS_PARTITION_LEVEL
MODEL_BASE_DIMENSION
RELATIONAL_ATTRIBUTE_DATA
RELATIONAL_MEASURE_DATA
SOLVE_BASE_MEAS
SOLVE_SOLVEDFN
SOLVE_SOURCE_MEAS

2 MODELs 22 VALUESETs


BALANCES_ACCOUNTS_AWXMLMODEL ACCOUNTS_AGGRDIM_VSET
BALANCES_BRANCHES_AWXMLMODEL ACCOUNTS_AGGRHIER_VSET
ACCOUNTS_HIER_LEVELS
ACCOUNTS_INHIER
ACCOUNTS_LOAD_STATUS_VSET
BRANCHES_AGGRDIM_VSET
BRANCHES_AGGRHIER_VSET
BRANCHES_HIER_LEVELS
BRANCHES_INHIER
BRANCHES_LOAD_STATUS_VSET
CALC_MEMBERS_IN_MODEL
CALC_MEMBER_OTHER_DIMENSIONS
CUBE_COMPOSITE_BASES
CUBE_DIMENSIONS
DEPENDENT_MEASURES
MEAS_COMPOSITE_BASES
MEAS_IN_FOLDER
MODEL_OTHER_DIMENSIONS
SOLVEDFN_CALCULATION_ORDER
SOLVEDFN_SOLVE_ORDER
SOLVE_ORDER
SOLVE_TARGET_MEAS

4 AGGMAPs 11 SURROGATEs


OBJ1962518006 ACCOUNTS_ACCOUNT_SURR
OBJ1962518006_PRT_PRTAGGMAP ACCOUNTS_HIERLIST_SURR
OBJ1962518006_PRT_RUNAGGMAP ACCOUNTS_LEVELLIST_SURR
OBJ1962518006_PRT_TOPAGGMAP ACCOUNTS_TOTAL_ACCOUNTS_SURR
BRANCHES_BRANCH_SURR
BRANCHES_HIERLIST_SURR
BRANCHES_LEVELLIST_SURR
BRANCHES_REGION_SURR
BRANCHES_TOTAL_BRANCHES_SURR
__XML_GENERATED_1
__XML_GENERATED_2

What we've got here is the two dimensions we've created (ACCOUNTS and BRANCHES), the measure BALANCES_BALANCE_STORED, and a whole load of additional objects that make up the standard form metadata. The measure, which we called BALANCES in the AWM Model view, is named within the AW using the format CUBENAME_MEASURENAME_STORED.

We can then take a look at the ACCOUNTS dimension that has been set up, listing out the member ID (taken from our ACCOUNT_ID source column) and the long description (taken from the ACCOUNT_DESC source column).

->rpr down accounts w 30 accounts_short_description
           --ACCOUNTS_SHORT_DESCRIPTION--
           --------ALL_LANGUAGES---------

ACCOUNTS ENGLISH_UNITED KINGDOM


TOTAL_ACCOUNTS All Accounts
_100
ACCOUNT_1 Wages
ACCOUNT_2 Sales

Do the same for the BRANCHES dimension,

->rpr down branches w 30 branches_short_description
           --BRANCHES_SHORT_DESCRIPTION--
           --------ALL_LANGUAGES---------

BRANCHES ENGLISH_UNITED KINGDOM


TOTAL_BRANCHES All Branches
_100
REGION_10 South-East
REGION_11 London
REGION_12 North-West
BRANCH_1 Brighton
BRANCH_2 Worthing
BRANCH_3 Charing Cross
BRANCH_4 Liverpool
BRANCH_5 Manchester

and then list out the contents of the measure.

->rpr balances_balance_stored
           -------------------------------------BALANCES_BALANCE_STORED--------------------------------------
           ---------------------------------------------BRANCHES---------------------------------------------
           TOTAL_BRAN

ACCOUNTS CHES_100 REGION_10 REGION_11 REGION_12 BRANCH_1 BRANCH_2 BRANCH_3 BRANCH_4 BRANCH_5


TOTAL_ACCOUNTS 760.00 210.00 225.00 325.00 130.00 80.00 NA NA NA
_100
ACCOUNT_1 360.00 90.00 100.00 170.00 50.00 40.00 100.00 80.00 90.00
ACCOUNT_2 400.00 120.00 125.00 155.00 80.00 40.00 125.00 60.00 95.00

Now, say that we wanted to create a new measure, that contained the percentage of sales that wages represented. This measure would have one dimension, BRANCHES, and would be calculated by taking the BALANCES measure for each branch and dividing wages by sales then multiplying by 100. We could do this at the relational end, creating a new table for this measure, calculating the percentage and then loading it into a RATIOS cube. Old Express hands though would create a formula instead, dimensioned by BRANCHES, that derived the value from the BALANCES measure.

->define wages_pct_of_sales formula decimal <BRANCHES>

->eq (BALANCES_BALANCE_STORED(ACCOUNTS 'ACCOUNT_1') / BALANCES_BALANCE_STORED(ACCOUNTS 'ACCOUNT_2'))*100

->update

->commit

which when queried would give the correct results:

->rpr wages_pct_of_sales
           WAGES_PCT_

BRANCHES OF_SALES


TOTAL_BRANCHES 90.00
_100
REGION_10 75.00
REGION_11 80.00
REGION_12 109.68
BRANCH_1 62.50
BRANCH_2 100.00
BRANCH_3 80.00
BRANCH_4 133.33
BRANCH_5 94.74

The problem with this approach though, is when you're working with Oracle OLAP and analytic workspaces creating the fornula isn't enough - to display it as a calculated measure in AWM and Discoverer for OLAP, you've got to create all the associated standard form metadata. Now whilst this is undoubtedly possible, it's by no means a simple affair (I've yet to get this working) and the metadata itself changes from release to release. Therefore, what you've got to do is take your formula definition and process it through AWM. Thanks for Anthony Waite and Bud Endress for explaining how this takes place.

The first step is to create a new cube, in my case called RATIOS, that will hold my new calculated measure. This cube will have one dimension, BRANCHES, as ACCOUNTS is being rolled up into the ratio. Note that the cube has no measures.

The next step then is to use a text editor to create an AWM template file. In my case, the template looked like this:

<Create Id="Action315475">
    <ActiveObject>
          <DerivedMeasure  Name="WAGES_PCT_OF_SALES" LongName="Wages % of Sales"
		   ShortName="Wages/Sales" PluralName="Wages % of Sales"
		   Id="RATIOS.WAGES_PCT_OF_SALES.MEASURE" DataType="decimal" isInternal="false"
		   UseGlobalIndex="false" ForceCalc="false" ForceOrder="false"
		   SparseType="STANDARD" AutoSolve="DEFAULT"
		   ExpressionText="(BALANCES_BALANCE_STORED(ACCOUNTS 'ACCOUNT_1') / BALANCES_BALANCE_STORED(ACCOUNTS 'ACCOUNT_2'))*100"/>
    </ActiveObject>
</Create>

The bits in bold are the bits that I had to change to suit my formula. Two points to note on this:

  1. The ID is made up of CUBE_NAME.FORMULA_NAME.MEASURE, where CUBE_NAME is the name of the one dimension cube I just set up, FORMULA_NAME is the name of my formula, and "MEASURE" is just a literal - i.e. just type in "MEASURE".
  2. The ExpressionText is the text of the formula definition, minus the "eq" at the start.

Save the template, and then right-click on the calculated measures node in the RATIOS cube, and create a calculated measure from the template file. Once the template is loaded, the new calculated measure should be visible within AWM.

Now, if you use the View Data option to look at the calculated measure within AWM, you should see the values as expected.

Note as well how the aggregation has been carried out for you, properly aggregating the percentages rather than just SUMming them up. As it's a formula, there's no need to separately process this cube - as long as the base data has been loaded and aggregated, the formula then picks up the values and displays them without further processing.

Finally, if I then go into the OLAP Worksheet again, I can view my formula and then display the values.

->listnames formulas
   2 FORMULAs
   -------------------------
   BALANCES_BALANCE
   RATIOS_WAGES_PCT_OF_SALES

->rpr ratios_wages_pct_of_sales

           RATIOS_WAG
           ES_PCT_OF_

BRANCHES SALES


TOTAL_BRANCHES 90.00
_100
REGION_10 75.00
REGION_11 80.00
REGION_12 109.68
BRANCH_1 62.50
BRANCH_2 100.00
BRANCH_3 80.00
BRANCH_4 133.33
BRANCH_5 94.74

The points to take away from this are that firstly, you're not restricted to just the calculations that AWM gives you (as long as you know a smattering of OLAP DML) and that secondly, if you want to manually create these calculations, don't try and create them using the OLAP Worksheet and OLAP DML, use AWM templates instead as the standard form metadata is automatically created for you, and the definition of the calculation is then preserved in the AW template and can be saved along with the rest of the AW definition.