Powered By

Free XML Skins for Blogger

Powered by Blogger

Friday, September 12, 2008

BW BI Transformation Creating Inversion Routines

Use

If you have defined routines in the transformation for a VirtualProvider, for performance reasons it may be useful to create inversion routines for these routines. In this way you can transform the selection criteria of a navigation step into selection criteria for the extractor. However, you do not require inversion routines to ensure the consistency of the data.

More information: Processing Selection Conditions

When you jump to a transaction in another SAP system using the report-report interface, you have to create an inversion routine for the transformation if you are using one, because otherwise the selections cannot be transferred to the source system.

You can create an inversion routine for all types of routine. The following rules apply:

With expert routines, there is no segmentation into conditions.

With start routines, the system performs segmentation into conditions. The system applies this to the complete source structure. The source structure is the start and end point.

With end routines, the target structure is the start and end point.

Prerequisites

You have already created a routine.

Procedure

You are in the routine editor. To create an inversion routine, enter the following:

...

1. Between *$*$ begin of inverse routine ... and *$*$ end of inverse routine ... enter your program code to invert the routine.

With an inversion routine for a VirtualProvider, it is sufficient if the value set is restricted in part. You do not need to specify an exact selection. The more exactly you restrict the selection, the better the system performance when you execute a query.

With an inversion routine for a jump using the report-report interface, you have to make an exact inversion so that the selections can be transferred exactly.

More information about the parameters of the routine: Parameters of Inversion Routines

2. Check the syntax of your routine.

3. Save the routine. You end the maintenance session for the routine by leaving the editor.

Example

An example for an inversion routine: Example for Inversion Routine

Inversion Routine Parameters BW BI Transformation Creating Inversion Routines

The inversion routine has method invert.

It has the following parameters:

Importing

i_th_fields_outbound: Fields/InfoObjects for the query structure

i_r_selset_outbound: Query selection conditions

i_is_main_selection: Allows you to transfer complex selection conditions such as selection conditions for columns.

i_r_selset_outbound_complete: All selections

i_r_universe_inbound: Description of source structure with regard to set objects.

Changing

c_th_fields_inbound: Fields/InfoObjects for the target structure

c_r_selset_inbound: Taget selection conditions. You can fill the target field from more than one source field. In this case, you have to define more than one condition.

c_exact: Allows you to specify whether you want the transformation of the selection criteria to be performed exactly. If the condition can be filled exactly, a direct call is possible. This is important when you call the report-report interface. If the condition cannot be filled exactly, a selection screen appears for the user.

Example for Inversion Routine BW BI Transformation Creating Inversion Routines

In this example, the German keys 'HERR' and 'FRAU' in the target characteristic are mapped to the English keys 'MR' and 'MRS' from the field PASSFORM (form of address) of the source. All other values from the source field are mapped to the initial value.

The coding of the routine is as follows:

This graphic is explained in the accompanying text

*---------------------------------------------------------------------*
* CLASS routine DEFINITION
*---------------------------------------------------------------------*
*
*---------------------------------------------------------------------*
CLASS lcl_transform DEFINITION.
PUBLIC SECTION.

TYPES:
BEGIN OF _ty_s_SC_1,
* Field: PASSFORM Anrede.
PASSFORM
TYPE C LENGTH 15,
END OF _ty_s_SC_1.
TYPES:
BEGIN OF _ty_s_TG_1,
* InfoObject: 0PASSFORM Anrede.
PASSFORM
TYPE /BI0/OIPASSFORM,
END OF _ty_s_TG_1.
PRIVATE SECTION.

TYPE-POOLS: rsd, rstr.

*$*$ begin of global - insert your declaration only below this line *-*
DATA p_r_set_mr TYPE REF TO cl_rsmds_set.
DATA p_r_set_mrs TYPE REF TO cl_rsmds_set.
DATA p_r_set_space TYPE REF TO cl_rsmds_set.

*$*$ end of global - insert your declaration only before this line *-*
METHODS
compute_0PASSFORM
IMPORTING
request
type rsrequest
datapackid
type rsdatapid
SOURCE_FIELDS
type _ty_s_SC_1
EXPORTING
RESULT
type _ty_s_TG_1-PASSFORM
monitor
type rstr_ty_t_monitor
RAISING
cx_rsrout_abort
cx_rsrout_skip_record
cx_rsrout_skip_val.
METHODS
invert_0PASSFORM
IMPORTING
i_th_fields_outbound
TYPE rstran_t_field_inv
i_r_selset_outbound
TYPE REF TO cl_rsmds_set
i_is_main_selection
TYPE rs_bool
i_r_selset_outbound_complete
TYPE REF TO cl_rsmds_set
i_r_universe_inbound
TYPE REF TO cl_rsmds_universe
CHANGING
c_th_fields_inbound
TYPE rstran_t_field_inv
c_r_selset_inbound
TYPE REF TO cl_rsmds_set
c_exact
TYPE rs_bool.
ENDCLASS. "routine DEFINITION
*$*$ begin of 2nd part global - insert your code only below this line *
...
"insert your code here
*$*$ end of 2nd part global - insert your code only before this line *

*---------------------------------------------------------------------*
* CLASS routine IMPLEMENTATION
*---------------------------------------------------------------------*
*
*---------------------------------------------------------------------*
CLASS lcl_transform IMPLEMENTATION.

METHOD compute_0PASSFORM.

* IMPORTING
* request type rsrequest
* datapackid type rsdatapid
* SOURCE_FIELDS-PASSFORM TYPE C LENGTH 000015
* EXPORTING
* RESULT type _ty_s_TG_1-PASSFORM

DATA:
MONITOR_REC
TYPE rsmonitor.

*$*$ begin of routine - insert your code only below this line *-*

CASE SOURCE_FIELDS-passform.
WHEN 'HERR'. RESULT = 'MR'.
WHEN 'FRAU'. RESULT = 'MRS'.
WHEN OTHERS. RESULT = space.
ENDCASE.

*$*$ end of routine - insert your code only before this line *-*
ENDMETHOD. "compute_0PASSFORM


The corresponding inversion routine is as follows:

This graphic is explained in the accompanying text

*$*$ begin of inverse routine - insert your code only below this line*-*
DATA l_r_set TYPE REF TO cl_rsmds_set.
IF i_r_selset_outbound->is_universal( ) EQ rsmds_c_boolean-true.

* If query requests all values for characteristic 0PASSNAME
* request also all values from source field PASSNAME
c_r_selset_inbound = cl_rsmds_set=>get_universal_set( ).
c_exact = rs_c_true.
"Inversion is exact

ELSE.
TRY.
IF me->p_r_set_mrs IS INITIAL.
* Create set for condition PASSFORM = 'FRAU'
me->p_r_set_mrs = i_r_universe_inbound->create_set_from_string(
'PASSFORM = ''FRAU''' ).
ENDIF.
IF me->p_r_set_mr IS INITIAL.
* Create set for condition PASSFORM = 'HERR'
me->p_r_set_mr = i_r_universe_inbound->create_set_from_string(
'PASSFORM = ''HERR''' ).
ENDIF.
IF me->p_r_set_space IS INITIAL.
* Create set for condition NOT ( PASSFORM = 'FRAU' OR PASSFORM = 'HERR' )
l_r_set = me->p_r_set_mr->unite( me->p_r_set_mrs ).
me->p_r_set_space = l_r_set->complement( ).
ENDIF.

* Compose inbound selection
c_r_selset_inbound = cl_rsmds_set=>get_empty_set( ).
* Check if outbound selection contains value 'MR'
IF i_r_selset_outbound->contains( 'MR' ) EQ rsmds_c_boolean-true.
c_r_selset_inbound = c_r_selset_inbound->unite( me->p_r_set_mr ).
ENDIF.
* Check if outbound selection contains value 'MRS'
IF i_r_selset_outbound->contains( 'MRS' ) EQ rsmds_c_boolean-true.
c_r_selset_inbound = c_r_selset_inbound->unite( me->p_r_set_mrs ).
ENDIF.
* Check if outbound selection contains initial value
IF i_r_selset_outbound->contains( space ) EQ rsmds_c_boolean-true.
c_r_selset_inbound = c_r_selset_inbound->unite( me->p_r_set_space ).
ENDIF.
c_exact = rs_c_true.
"Inversion is exact

CATCH cx_rsmds_dimension_unknown
cx_rsmds_input_invalid
cx_rsmds_sets_not_compatible
cx_rsmds_syntax_error.

* Normally, should not occur
* If the exception occurs request all values from source
* for this routine to be on the save side
c_r_selset_inbound = cl_rsmds_set=>get_universal_set( ).
c_exact = rs_c_false.
"Inversion is no longer exact

ENDTRY.
ENDIF.

* Finally, add (optionally) further code to transform outbound projection
* to inbound projection
* Check if outbound characteristic 0PASSFORM (field name PASSFORM)
* is requested for the drilldown state of the query
READ TABLE i_th_fields_outbound
WITH TABLE KEY segid = 1 "Primary segment
fieldname =
'PASSFORM'
TRANSPORTING NO FIELDS.
IF sy-subrc EQ 0.
* Characteristic 0PASSFORM is needed
* ==> request (only) field PASSFORM from the source for this routine
DELETE c_th_fields_inbound
WHERE NOT ( segid EQ 1 OR
fieldname
EQ 'PASSFORM' ).
ELSE.
* Characteristic 0PASSFORM is not needed
* ==> don't request any field from source for this routine
CLEAR c_th_fields_inbound.
ENDIF.

*$*$ end of inverse routine - insert your code only before this line *-*
ENDMETHOD. "invert_0PASSFORM
ENDCLASS. "routine IMPLEMENTATION

Details for Implementing the Inversion Routine BW BI Transformation Creating Inversion Routines

Set Objects

The purpose of an inverse transformation is to convert selection conditions of the query that are formulated for the target of the transformation (outbound) into selection conditions for the source (inbound). To do this, the selection conditions are converted into a multidimensional set object. In ABAP objects, these are the instances of class CL_RSMDS_ST). The advantage of this representation is that set operations (intersection, union, and complement) that can only be processed at high cost with the usual RANGE table representation can now be processed easily.

Universes

There are always two uniquely defined trivial instances of class CL_RSMDS_SET that represent the empty set and the total set (that is, all the values). You can recognize these instances from the result RSMDS_C_BOOLEAN-TRUE of the functional methods IS_EMPTY and IS_UNIVERSAL. All other instances are always assigned to a Universe (instance of class CL_RSMDS_UNIVERSE) and return the result RSMDS_C_BOOLEAN-TRUE for the specified methods. You can get the reference of the assigned universe for non-trivial instances of class CS_RSMDS_SET with method GET_UNIVERSE. This method returns an initial reference for these two trivial instances since the universe is not uniquely defined in this case.

A universe represents the sum of all the dimensions (represented by instances of the interface IF_RSMDS_DIMENSION). A dimension is always uniquely defined by a dimension name in the universe. With method GET_DIMENSION_BY_NAME in class CL_RSMDS_UNIVERSE, you can get a dimension reference using the unique dimension name. The dimension name is generally the same as the field name in a structure. There are different types of universe in the system (subclasses of class CL_RSMDS_UNIVERSE). The dimensions have different meanings. For example, a dimension corresponds to an InfoObject in class CL_RS_INFOOBJECT_UNIVERSE. In the case of InfoObjects, you have the two methods IOBJNM_TO_DIMNAME and DIMNAME_TO_IOBJNM that transform an InfoObject name into a dimension name or a dimension name into an InfoObject name. For an InfoObject-based universe, there is exactly one instance (singleton) that contains (nearly) all the active InfoObjects in the system as dimensions (with the exception of InfoObjects in InfoSets). This instance is returned with the method GET_INSTANCE of class CL_RS_INFOOBJECT_UNIVERSE.

In the case of DataSources, there is a uniquely defined universe for each combination of logical system name (I_LOGSYS), DataSource name (I_DATASOURCE) and segment ID (I_SEGID). You can find the reference of the universe with the method CREATE_FROM_DATASOURCE_KEY of class CL_RSDS_DATASOURCE_UNIVERSE. The initial segment ID always provides the primary segment, which normally is the only segment on which selection conditions can be formulated for a source and accepted. All the fields in the DataSource segment that are selected for direct access form the dimensions of a DataSource universe with the same name. Here, too, you get a dimension reference (instance for interface IF_RSMDS_DIMENSION) with the method GET_DIMENSION_BY_NAME of the universe.

If you want to project a selection to a given dimension from a general selection, that is for any instance of the class CL_RSMDS_SET, you first need a reference to the universe to which the instance belongs (method GET_UNIVERSE, see above). You get the dimension reference from the reference to the universe using the dimension/field name from method GET_DIMENSION_BY_NAME. With the dimension reference, you can then project a representation for a one-dimensional condition using method TO_DIMENSION_SET. You can then convert a one-dimensional projection into an Open SQL or RANGE condition for the corresponding field with the methods TO_STRING and TO_RANGES. Vice versa, you can create an instance on the dimension reference for a one-dimensional set object from a RANGE table using the method CREATE_SET_FROM_RANGES. The SIGNs 'I' and 'E' as well as the OPTIONs 'EQ', 'NE', 'BT', 'NB', 'LE', 'GT', 'LT', 'GE', 'CP' and 'NP' are supported. There are only restrictions for 'CP' and 'NP'. These may only be used for character-type dimensions/fields and may only contain the masking character'*', which must always be at the end of the character chain. For example, 'E' 'NP' 'ABC*' is a valid condition, but 'I' 'CP' '*A+C*' is not.

Using method GET_DIMENSIONS in class CL_RSMDS_SET, you can get a table with the references of all dimensions that are restricted in the corresponding instance of the set object. With the method GET_NAME, you can get the unique dimension name for each dimension reference in the table that is returned. In this way you can check if there is a restriction for a given InfoObject or field. It can be projected as described above.

With the universe reference, you can create an instance for a set object (especially for multidimensional set objects) from an Open SQL expression. In the Open SQL expression that is passed, the "field names" must be the valid dimension names in the universe. You may use elementary conditions with the comparison operators '=', '<>', '<=', '>', '<' und '>=' in the Open SQL expression. The left side must contain a valid dimension name and the right side must contain a literal that is compatible with the data type of the dimension. You can also use elementary conditions with 'BETWEEN', 'IN' and 'LIKE' using the appropriate syntax. Elementary conditions may be linked with the logical operators 'NOT', 'AND' and 'OR' to create complex conditions. You may also use parentheses to change the normal order of evaluation ('NOT' is stronger than 'AND', 'AND' is stronger than 'OR').

With the method CREATE_SET_FROM_RANGES of the universe reference, you can also directly create a set object for a multidimensional condition. To do this, the internal table passed in I_T_RANGES must contain a RANGE structure (with the components SIGN, OPTION, LOW and HIGH) in its row structure and must also have an additional component for a dimension name. Parameter I_FIELDNAME_DIMENSION must pass the name of these components to method CREATE_SET_FROM_RANGES.

You can always create an instance for the complementary condition for any instance of the class CL_RSMDS_SET using the functional method.

If two instances of the class CL_RSMDS_SET belong to the same universe, you can create an instance for the intersection or union by passing the other instance as parameter I_R_SET when you call the functional method INTERSECT or UNITE.

With the method TRANSFORM, you can also transform an instance of a set object into an instance of a set object of another universe. If required, you can thus perform a projection or assign dimension names in a different manner. These methods are recommended for example if the name of the source field differs from the name of the target field within the transformation. You can pass a reference to the target universe to the method in the optional parameter I_R_UNIVERSE. If the parameter remains initial, the system assumes that the source and target universes are identical. With parameter I_TH_DIMMAPPINGS you can represent the dimension names of the source universe (component DIMNAME_FROM) in different dimension names on the target universe (component DIMNAME_TO). If component DIMNAME_TO remains initial, a restriction of the source dimension (in DIMNAME_FROM) is not transformed into a restriction of the target universe. As a result, there is a projection. The following mapping table

DIMNAME_FROM

DIMNAME_TO

AIRLINEID

CARRID

CONNECTID

CONNID

FLIGHTDATE


transforms a set object that corresponds to the Open SQL condition

AIRLINEID = 'LH' AND CONNECTID = '0400' AND FLIGHTDATE = '20070316' OR

AIRLINEID = 'DL' AND CONNECTID = '0100' AND FLIGHTDATE = '20070317'

into a set object that corresponds to the Open SQL condition

CARRID = 'LH' AND CONNID = '0400' OR

CARRID = 'DL' AND CONNID = '0100',

for example.

Start and End Routines

Parameters I_R_SELSET_OUTBOUND and I_R_SELSET_OUTBOUND_COMPLETE are passed to the start and end routines for the transformation of the selection conditions. The references passed in the two parameters are identical for simple queries, and parameter I_IS_MAIN_SELECTION is defined by the constant RS_C_TRUE. For complex queries that for example contain restricted key figures or structure elements with selections, the inverse start routine is called several times. The first time, I_R_SELSET_OUTBOUND is called with the restrictions from the global filter and the restrictions that are shared by all structure elements. In this call, parameter I_IS_MAIN_SELECTION is also set to RS_C_TRUE. There are further calls with selections for the specific structure element. However, they are combined so that they no longer overlap. In these calls, I_IS_MAIN_SELECTIN is set to RS_C_FALSE. The complete selection condition is contained in I_R_SELSET_OUTBOUND_COMPLETE for all calls. In order to transform the selections exactly in the start and end routines, the transformation of I_R_SELSET_OUTBOUND into a set object C_R_SELSET_INBOUND in the universe of the source structure (is passed as a reference with parameter I_R_UNIVERSE_INBOUND) must be made exactly for each call. This must be documented by returning the value RS_C_TRUE in parameter C_EXACT.

Expert Routines

Parameter I_R_SELSET_OUTBOUND always passes the complete selections of the target to the expert routine. The expert routine must return a complete selection for the source in C_R_SELSET_INBOUND. As previously for the start and end routines, it could be advantageous to break a complex selection S down into a global selection G and several disjunct subsections Ti (i = 1...n). You can break down the passed reference with the method GET_CARTESIAN_DECOMPOSITION. Parameter E_R_SET contains the global selection; the subselections are entries in the internal table that is returned in parameter E_TR_SETS. For the decomposition, the following is always valid: S = G Ç (T1 ÈÈ Tn ) and Ti Ç Tj = Æ for i ¹ j. You should invert the global selection and each subselection individually ( G -> G', Ti -> Ti') and compose the inverted results again in the form G' Ç (T1' ÈÈ Tn ' ). Generally you can only ensure an exact inversion of a complex selection condition by using such a decomposition. If the method GET_CARTESIAN_DECOMPOSITION is called with I_REDUCED = RSMDS_C_BOOLEAN-FALSE, the following is already valid for the decomposition S = (T1 ÈÈ Tn ). This is no longer true for a call with I_REDUCED = RSMDS_C_BOOLEAN-TRUE, and (T1 ÈÈ Tn ) is usually a superset of S. In this case the selections Ti are usually simpler.

Passing the Selection Conditions

If the transformed selection conditions for the source return exactly the data records that satisfy the selection conditions of the target after execution of the transformation, then the inverse transformation is considered to be exact. This will not always be possible. For this reason a transformation that is not exact may provide more data records/sets than are needed to satisfy the selection conditions of the target. You can ensure that the results are exact by filtering them with the selection conditions of the target. An inverse transformation, however, should not create a selection condition for the source that selects fewer data records/sets from the source than are needed to satisfy the selection condition of the target.

An inverse transformation that is not exact is indicated by the return value RS_C_FALSE in parameter C_EXACT for at least one inverse routine run. This only has an effect on the performance for queries on the Analytic Engine (OLAP) since they are always filtered again there. In the RSDRI interface, in transaction LISTCUBE, and in function Display Data in the context menu of a VirtualProviders, however, there is no further filtering and the superfluous records/sets are returned or displayed. The property of being exact for an inverse transformation otherwise only has an effect if it is called in the report-report interface. An inversion that is not exact always causes the selection screen to be displayed before the target transaction is executed. This gives the user the chance to check the selections again and to correct them if necessary.

An inverse routine that is not implemented always requests all the values for all the source fields of this routine. Accordingly, parameters C_R_SELSET_INBOUND and C_EXACT always contain an instance for the "All Values" condition or the value RS_C_FALSE when they are called.

One final comment. Selections are always stored in a normed manner in a set object. This means, for example, that the two Open SQL expressions

CARRID = 'LH' AND FLDATE < '20070101'

and

CONNID <= '20061231' AND CARRID = 'LH'

have the same representation as the set object. If you call all the methods that cause the creation of a set object as result with the parameter I_FINAL = RSMDS_C_BOOLEAN-TRUE (this should normally be the default value), you must also make sure that the two objects are identical in the above case (that is, they should have the same references). To check if two instances of the class CL_RSMDS_SET represent the same selection condition, however, you should nevertheless use the method IS_EQUAL and check against the result RSMDS_C_BOOLEAN-TRUE.

Regular Expressions in Routines BW BI Transformation Creating Inversion Routines

Use

You can use regular expressions in routines.

A regular expression (abbreviation: RegExp or Regex) is a pattern of literal and special characters which describes a set of character strings. In ABAP, you can use regular expressions in the FIND and REPLACE statements, and in classes CL_ABAP_REGEX and CL_ABAP_MATCHER. For more information, see the ABAP key word documentation in the ABAP Editor. This documentation describes the syntax of regular expressions and you can test regular expressions in the ABAP Editor.

Example

This section provides sample code to illustrate how you can use regular expressions in routines.

This graphic is explained in the accompanying text

REPORT z_regex.

DATA: l_input TYPE string,

l_regex TYPE string,

l_new TYPE string.

* Example 1: Insert thousand separator

l_input = '12345678'.

l_regex = '([0-9])(?=([0-9]{3})+(?![0-9]))'.

l_new = '$1,'.

WRITE: / 'Before:', l_input. "12345678

REPLACE

ALL OCCURRENCES OF

REGEX l_regex

IN l_input WITH l_new.

WRITE: / 'After:', l_input. "12,345,678

* Example 2: Convert date in US format to German format

l_input = '6/30/2005'.

l_regex = '([01]?[0-9])/([0-3]?[0-9])/'.

l_new = '$2.$1.'.

WRITE: / 'Before:', l_input. "6/30/2005

REPLACE

ALL OCCURRENCES OF

REGEX l_regex

IN l_input WITH l_new.

WRITE: / 'After:', l_input. "30.6.2005

* Example 3: Convert external date in US format to internal date

DATA: matcher TYPE REF TO cl_abap_matcher,

submatch1 TYPE string,

submatch2 TYPE string,

match TYPE c.

l_input = '6/30/2005'.

l_regex = '([01]?)([0-9])/([0-3]?)([0-9])/([0-9]{4})'.

matcher = cl_abap_matcher=>create( pattern = l_regex

text = l_input ).

match = matcher->match( ).

TRY.

CALL METHOD matcher->get_submatch

EXPORTING

index = 1

RECEIVING

submatch = submatch1.

CATCH cx_sy_matcher.

ENDTRY.

TRY.

CALL METHOD matcher->get_submatch

EXPORTING

index = 3

RECEIVING

submatch = submatch2.

CATCH cx_sy_matcher.

ENDTRY.

IF submatch1 IS INITIAL.

IF submatch2 IS INITIAL.

l_new = '$5\0$2\0$4'.

ELSE.

l_new = '$5\0$2$3$4'.

ENDIF.

ELSE.

IF submatch2 IS INITIAL.

l_new = '$5$1$2\0$4'.

ELSE.

l_new = '$5$1$2$3$4'.

ENDIF.

ENDIF.

WRITE: / 'Before:', l_input. "6/30/2005

REPLACE

ALL OCCURRENCES OF

REGEX l_regex

IN l_input WITH l_new.

WRITE: / 'After:', l_input. "20050630