Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 

Merge ranges logically via ABAP coding

alex_geppart
Active Participant

I have the requirement to logically merge two range tables (table a and table b) into a third range table c.

Afterwards this range table c should be used in the SELECT statement.

Both range tables refer to the same data element and can contain n entries.

If there are contradictory conditions, the condition from table b should always be used.

In my view, this task could be solvable with the set theory.

The input could look like this:

range_table_a = value #( ( sign = 'I' option = 'EQ' low = 'Z001' ) 
                         ( sign = 'I' option = 'EQ' low = 'Z002') ); 

range_table_b = value #( ( sign = 'E' option = 'EQ' low = 'Z002') ); 

I would expect this result after a logical merge of range_table_a and range_table_b:

range_table_c = value #( ( sign = 'I' option = 'EQ' low = 'Z001' )
                         ( sign = 'E' option = 'EQ' low = 'Z002' ) ); 

Has anyone seen anything about this in the SAP standard?

1 ACCEPTED SOLUTION

alex_geppart
Active Participant

It seems I caused some confusion with my question and try to correct it.

In the current use case we have a report that runs every day with different predefined report variants.

These are fixed per day and time and consist mostly of range tables.

But sometimes it is necessary to make a temporary change to the variant for a certain program run. In order to avoid changing the variant in the productive system just for 2 hours and revert it afterwards, this short-term change was requested as an "exception" via customizing direct in the production. This temporary exception should have a higher priority than the range table entries from standard variants.

I'm not completely done with development yet, but most requested test cases working already:

  METHOD check_combinations.
    check_combination(
         iv_test_name       = 'No conflict - higher and lower prio range must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z002' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'EQ' low  = 'Z001' )
                                                 ( sign  =  'I' option = 'EQ' low  = 'Z002' ) ) ).
    check_combination(
         iv_test_name       = 'Conflict - only higher prio range must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'E' option = 'EQ' low  = 'Z001' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'E' option = 'EQ' low  = 'Z001' ) ) ).

    check_combination(
         iv_test_name       = 'Conflict - only higher prio range must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'E' option = 'EQ' low  = 'Z001' )
                                               ( sign  =  'I' option = 'EQ' low  = 'Z002' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'E' option = 'EQ' low  = 'Z001' )
                                                 ( sign  =  'I' option = 'EQ' low  = 'Z002' ) ) ).
    check_combination(
         iv_test_name       = 'Partly conflict - higher prio range and part of lower table must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z002' )
                                               ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'E' option = 'EQ' low  = 'Z001' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'EQ' low  = 'Z002' )
                                                 ( sign  =  'E' option = 'EQ' low  = 'Z001' ) ) ).
    "Between Checks
    check_combination(
         iv_test_name       = 'No Conflict - all of higher prio range and of lower prio table must be used'
         it_lower_prio      = VALUE ttr_kunwe( ( sign  =  'I' option = 'BT' low  = '1000' high = '2000' ) )
         it_higher_prio     = VALUE ttr_kunwe( ( sign  =  'I' option = 'BT' low  = '1999' high = '2005') )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'BT' low  = '1000' high = '2005' ) ) ).

    check_combination(
         iv_test_name       = 'Conflict - higher prio range must be used as it is the oposite of lower prio'
         it_lower_prio      = VALUE ttr_kunwe( ( sign  =  'E' option = 'BT' low  = '1000' high = '2000' ) )
         it_higher_prio     = VALUE ttr_kunwe( ( sign  =  'I' option = 'EQ' low  = '1001' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'EQ' low  = '1001' ) ) ).


  ENDMETHOD.

My solution is based the standard class CL_RSMDS_DDIC_UNIVERSE.

So everyone who has a similar use case, just check Report RSMDS_DEMO to understand how to use this set API:

For me this question is resolved.

13 REPLIES 13

michael_piesche
Active Contributor

I gotta say, even though there might hopefully a „good“ business case behind this, it surely does sound like a very strange requirement.

Are you aware of how many combinations with sign, option, low and high are possible and that for each of your range-tables. You would have to go through each entry of the first table and based on its four values check if this is explicitly included, explicitly excluded, partially included or excluded or not treated at all by the entire second range table (unless there are restrictions on what kind of ranges can be in the two tables).

Where do the values for these come from? Because a person should be able to clearly define the select-options for one „table“ already, to do the required selection.

Sandra_Rossi
Active Contributor

I never found anything. I usually keep the ranges tables as they are, never merging them physically, except at the last moment directly in the WHERE of SELECT or LOOP:

...
WHERE field IN range_table_a 
  AND field IN range_table_b
  ...

alex_geppart
Active Participant

So far I have found class cl_rsmds_ddic_universe.

Checked its possibilities with report RSMDS_DEMO and saw the provided unit tests.

Using Methods like create_set_from_ranges, unite, intersect and then convert it back
via to_ranges() seems like that is what I was searching for.

In the next days I will build a test base for my usecase using this library from sap and see how it goes.

I will keep this question updated.

0 Kudos

I'm interested to know how you use this class to merge ranges. And even the logic behind. And also what is the business (or technical) case. I hope you'll have time to investigate and publish a blog post or at least a little code snippet.

vineet_gupta3
Participant

Another option would be to use select from valid values of the data element for each range. Then add the returned values into a new range with I EQ Value pattern.

0 Kudos

Hi Vineet, do you have a code snippet for you mentioned option?
Currently, I'm not able to understand what you mean.

For example if Table 1 has list of value for field1 on which the ranges are based:

select field1 from table1 into table range_a_itab where field1 = range_a

select field1 from table1 into table range_b_itab where field1 = range_b

Now use entries in range_a_itab and range_b_itab to create range_c

FredericGirod
Active Contributor
0 Kudos

For me it is possible in specific.

You have to transform the ranges in a list of single value (to avoid the LOW / HIGH values).

You have to add the entries of table B to the table C.

You have to loop on table A to check if the entry is already present or not, if not add it

and you have to rebuild the BT values (if several values, with same SIGN OPTION is concecutive, you could replace it by a BT).

not so complex

Transform in list of single values:

How do you transform ranges or patterns in single values without making a query to know what actual values exist, or do you want to do that for all values possible based on the datatype? What about numbers, decimals, text and string values?

Considering the given values from the question, 'Z001' and 'Z002', I assume it comes from a customizing table, and therefore there shouldnt be too many values possible, so it is very feasible, but then one would already implement limitiations to the original request: Combine a range table A with range table B into a range table C, whereas B has priority for 'contradictory conditions'.

What is a "contradictory condition"?

For the given example:

  • range A selects Z001 as well as Z002
  • range B selects everything except Z002
  • the simple combination of range A and B selects only Z001
  • the 'combined' range C with 'handling of contradictory condition" selects only Z001

So here, simply combining A and B without the check for "contradictory conditions" would already lead to the requested result, the whole discussion wouldnt even be necessary.

A real contradiction would however be the following, imho:

  • range A selects only Z002
  • range B selects everything except Z002
  • the simple combination of range A and B selects nothing
  • the 'combined' range C with 'handling of contradictory condition" would select everything except Z002

Now is that the expected result? Based on the question I would say yes, but we still dont know the business case.

Ryan-Crosby
Active Contributor
0 Kudos

Hi Alexander,

Another option for this type of problem could be to let the database do the intersection of the two sets by using a join and having each of the range tables reflect on the left/right sides of the WHERE clause accordingly.

Regards,

Ryan Crosby

michael_piesche
Active Contributor
0 Kudos

alexander.geppart, please follow up on your open question.

  • comment answers or your question if there are still open issues.
  • otherwise mark an answer as accepted if it helped you solve your problem
  • or post an answer of yourself and accept it if you found another useful solution yourself
  • or redirect your question to another question that is related and was useful to solve your problem
  • in the end, close your question

alex_geppart
Active Participant

It seems I caused some confusion with my question and try to correct it.

In the current use case we have a report that runs every day with different predefined report variants.

These are fixed per day and time and consist mostly of range tables.

But sometimes it is necessary to make a temporary change to the variant for a certain program run. In order to avoid changing the variant in the productive system just for 2 hours and revert it afterwards, this short-term change was requested as an "exception" via customizing direct in the production. This temporary exception should have a higher priority than the range table entries from standard variants.

I'm not completely done with development yet, but most requested test cases working already:

  METHOD check_combinations.
    check_combination(
         iv_test_name       = 'No conflict - higher and lower prio range must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z002' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'EQ' low  = 'Z001' )
                                                 ( sign  =  'I' option = 'EQ' low  = 'Z002' ) ) ).
    check_combination(
         iv_test_name       = 'Conflict - only higher prio range must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'E' option = 'EQ' low  = 'Z001' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'E' option = 'EQ' low  = 'Z001' ) ) ).

    check_combination(
         iv_test_name       = 'Conflict - only higher prio range must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'E' option = 'EQ' low  = 'Z001' )
                                               ( sign  =  'I' option = 'EQ' low  = 'Z002' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'E' option = 'EQ' low  = 'Z001' )
                                                 ( sign  =  'I' option = 'EQ' low  = 'Z002' ) ) ).
    check_combination(
         iv_test_name       = 'Partly conflict - higher prio range and part of lower table must be used'
         it_lower_prio      = VALUE ttr_auart( ( sign  =  'I' option = 'EQ' low  = 'Z002' )
                                               ( sign  =  'I' option = 'EQ' low  = 'Z001' ) )
         it_higher_prio     = VALUE ttr_auart( ( sign  =  'E' option = 'EQ' low  = 'Z001' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'EQ' low  = 'Z002' )
                                                 ( sign  =  'E' option = 'EQ' low  = 'Z001' ) ) ).
    "Between Checks
    check_combination(
         iv_test_name       = 'No Conflict - all of higher prio range and of lower prio table must be used'
         it_lower_prio      = VALUE ttr_kunwe( ( sign  =  'I' option = 'BT' low  = '1000' high = '2000' ) )
         it_higher_prio     = VALUE ttr_kunwe( ( sign  =  'I' option = 'BT' low  = '1999' high = '2005') )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'BT' low  = '1000' high = '2005' ) ) ).

    check_combination(
         iv_test_name       = 'Conflict - higher prio range must be used as it is the oposite of lower prio'
         it_lower_prio      = VALUE ttr_kunwe( ( sign  =  'E' option = 'BT' low  = '1000' high = '2000' ) )
         it_higher_prio     = VALUE ttr_kunwe( ( sign  =  'I' option = 'EQ' low  = '1001' ) )
         it_expected_result = VALUE range_c10_t( ( sign  =  'I' option = 'EQ' low  = '1001' ) ) ).


  ENDMETHOD.

My solution is based the standard class CL_RSMDS_DDIC_UNIVERSE.

So everyone who has a similar use case, just check Report RSMDS_DEMO to understand how to use this set API:

For me this question is resolved.

0 Kudos

Thank you for the feedback.