2020 Feb 12 6:17 PM
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?
2020 May 14 7:54 PM
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.
2020 Feb 12 7:14 PM
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.
2020 Feb 12 7:41 PM
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
...
2020 Feb 13 10:54 AM
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.
2020 Feb 18 2:54 PM
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.
2020 Feb 13 9:35 PM
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.
2020 Feb 14 8:16 AM
Hi Vineet, do you have a code snippet for you mentioned option?
Currently, I'm not able to understand what you mean.
2020 Feb 14 3:39 PM
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
2020 Feb 18 8:36 AM
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
2020 Mar 03 12:35 PM
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:
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:
Now is that the expected result? Based on the question I would say yes, but we still dont know the business case.
2020 Feb 18 3:00 PM
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
2020 May 13 1:40 PM
alexander.geppart, please follow up on your open question.
2020 May 14 7:54 PM
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.
2020 May 14 11:42 PM