I would like to convert the method below to a nested FOR instead of a nested LOOP, but I don't know how to do it since the inner table is dynamic (it can be one of 5 different types).
TYPES: BEGIN OF ty_result,
lgart TYPE string,
betrg TYPE string,
betpe TYPE string,
END OF ty_result,
ty_results TYPE STANDARD TABLE OF ty_result WITH EMPTY KEY.
DATA: known_table TYPE ty_results,
also_known_table TYPE ty_results,
mt_period_results TYPE ty_results.
FIELD-SYMBOLS: <dynamic_table> TYPE STANDARD TABLE,
<betrg>, <betpe>, <lgart>.
LOOP AT known_table REFERENCE INTO DATA(known_line).
READ TABLE <dynamic_table> TRANSPORTING NO FIELDS WITH KEY ('LGART') = known_line->*-lgart.
IF sy-subrc <> 0. CONTINUE. ENDIF.
DATA(lv_tabix) = sy-tabix.
LOOP AT <dynamic_table> ASSIGNING FIELD-SYMBOL(<dynamic_line>) FROM lv_tabix.
UNASSIGN: <betrg>, <betpe>, <lgart>.
ASSIGN COMPONENT: 'BETPE' OF STRUCTURE <dynamic_line> TO <betpe>,
'BETRG' OF STRUCTURE <dynamic_line> TO <betrg>,
'LGART' OF STRUCTURE <dynamic_line> TO <lgart>.
IF <lgart> <> known_line->*-lgart.
EXIT.
ENDIF.
APPEND VALUE ty_result( lgart = <lgart>
betrg = <betrg>
betpe = <betpe> ) TO mt_period_results.
ENDLOOP.
ENDLOOP.
When the inner table is not dynamic, I can do it like this:
append lines of value zwta_t_results(
for known_line in known_table
for also_known_line in also_known_table
where ( lgart = known_line-lgart )
( lgart = known_line-lgart
betrg = also_known_line-betrg
betpe = also_known_line-betpe ) to mt_period_results.
So the question is: is it possible to use FOR iterator (as the second method) with a dynamic table?
My answer was checked for ABAP 7.52. Unfortunately, it's currently only possible to use a subset of the static variant of ASSIGN by using LET <fs> = writable_expression IN inside a construction expression (including "FOR" table iterations), where the "writable expression" is limited to a table expression, NEW and CAST. So it's rather limited, there are no equivalences for the dynamic variants of ASSIGN, so you can use only workarounds.
The syntax after WHERE allows a dynamic expression, so it will be possible to enter WHERE ('LGART = KNOWN_LINE-LGART'). However, it could be very counter-performing if the loop is nested inside another loop (as it is in your case), so an index should be defined so that to accelerate the iteration. If a secondary index is to be used, then the condition should be USING KEY ('KEYNAME') WHERE ('LGART = KNOWN_LINE-LGART').
Now, here is a workaround for your particular case: you define statically the names of the components, so one possibility is to define a static structure with those component names and use the CORRESPONDING construction operator. Note that I didn't test it, but I think for several reasons that the performance of using CORRESPONDING is faster in your case than using ASSIGN.
The following code should work. I assume that the internal table behind <dynamic_table> has a primary key sorted by LGART (TYPE SORTED TABLE OF ... WITH NON-UNIQUE KEY lgart) so that the performance is good:
TYPES: BEGIN OF ty_struc,
lgart TYPE string,
betrg TYPE string,
betpe TYPE string,
END OF ty_struc.
known_table = VALUE #( ( lgart = 'A' ) ( lgart = 'B' ) ).
also_known_table = VALUE #( ( lgart = 'A' ) ( lgart = 'C' ) ( lgart = 'A' ) ).
ASSIGN also_known_table TO <dynamic_table>.
APPEND LINES OF
VALUE ty_results(
FOR known_line IN known_table
FOR <inner_line> IN <dynamic_table>
WHERE ('LGART = KNOWN_LINE-LGART')
LET struc = CORRESPONDING ty_struc( <inner_line> ) IN
( lgart = known_line-lgart
betrg = struc-betrg
betpe = struc-betpe ) )
TO mt_period_results.
Related
I want to pass a range table for OBJNR, e.g.
call method ME->ME_GET_STATUS
exporting
I_OBJNR = <FS_DATA>-OBJNR_NTF
I_AEDAT = LV_AEDAT
I_AEZEIT = LV_AEZEIT
IT_OBJNR = LR_OBJNR
importing ...
In the PUBLIC section of the super class I have:
RT_OBJNR type range of JSTO-OBJNR . (this is inherited by the calling class)
which is used by both calling & called methods.
The method ME_GET_STATUS has a parameter:
IT_OBJNR Importing Type RT_OBJNR Range table for OBJNR
and code
,WA_OBJNR like line of IT_OBJNR
,LR_OBJNR type RT_OBJNR
LR_OBJNR[] = IT_OBJNR[].
The range table is only used to buffer an itab - LT_JCDS.
select S~OBJNR, S~STAT, S~CHGNR, S~UDATE, S~UTIME,
S~INACT, O~OBTYP, O~STSMA
from JCDS as S
join JSTO as O
on O~OBJNR = S~OBJNR
into table #IT_JCDS
where S~OBJNR in #LR_OBJNR
order by S~OBJNR, S~UDATE, S~UTIME, S~STAT, S~CHGNR
loop at IT_JCDS into data(LT_JCDS)
where OBJNR = I_OBJNR
group by ( OBJNR = LT_JCDS-OBJNR STAT = LT_JCDS-STAT
GS = group size GI = group index )
ascending
reference into data(OBJNR_REF)
It all works perfectly if there is just 1 record in the range table.
The issue is that if I pass more than 1 record it still works fine but seems to cause a commit (?) which closes the cursor causing a dump in MCEX_BW_LO_API. This occurs when calling the macro "sel" for the 2nd data package.
The idea is to pass multiple records of 'EQ' and 'BT' selections resulting in fewer records being returned from the database.
I've tried changing to a standard table and using = LR_OBJNR[]
I have two nested structure and I want to map the field at runtime according to some rules. It can append that the field of the dest structure and the source structure are on different level of the nested structures.
(The structures have different types)
For example I want to map:
struct1-a1 = struct2-bsub1-s1_b1.
struct1-asub1-s1_a1 = struct2-b1.
DATA:
BEGIN OF struct1,
a1 TYPE string VALUE 'a1',
a2 TYPE string VALUE 'a2',
a3 TYPE string VALUE 'a3',
a4 TYPE string VALUE 'a4',
a5 TYPE string VALUE 'a5',
BEGIN OF asub1,
s1_a1 TYPE string VALUE 's1_a1',
s1_a2 TYPE string VALUE 's1_a2',
s1_a3 TYPE string VALUE 's1_a3',
END OF asub1,
END OF struct1,
BEGIN OF struct2,
b1 TYPE string VALUE 'b1',
b2 TYPE string VALUE 'b2',
b3 TYPE string VALUE 'b3',
a4 TYPE string VALUE 'b4',
a5 TYPE string VALUE 'b5',
BEGIN OF bsub1,
s1_b1 TYPE string VALUE 's1_b1',
s1_b2 TYPE string VALUE 's1_b2',
s1_b3 TYPE string VALUE 's1_b3',
END OF bsub1,
END OF struct2.
I found this cool class to build mapping for fields, but it has only one level parameter.
My question is can I use the class CL_ABAP_CORRESPONDING to map fields on different levels and how can I do it.
No, you can't, mapped structures must be on the same level. Excerpt from the class docu:
Notes
Components can only be mapped to each other if they are on the same level. Components in a substructure cannot be assigned to the components at higher levels, nor higher level components to components in a substructure.
You must split into several executions:
cl_abap_corresponding=>create(
source = struct2-bsub1
destination = struct1
mapping = VALUE cl_abap_corresponding=>mapping_table(
( level = 0 kind = 1 srcname = 's1_b1' dstname = 'a1' ) )
)->execute( EXPORTING source = struct2-bsub1
CHANGING destination = struct1 ).
cl_abap_corresponding=>create(
source = struct2
destination = struct1-asub1
mapping = VALUE cl_abap_corresponding=>mapping_table(
( level = 0 kind = 1 srcname = 's1_a1' dstname = 'b1' ) )
)->execute( EXPORTING source = struct2
CHANGING destination = struct1-asub1 ).
EDIT: although the documentation seems straight forward, I found out that the component selector may be used inside the SRCNAME component, to refer to a component from a nested structure, e.g. the first execution above is equivalent to this code (the differences are in source = struct2 and in srcname = 'bsub1-s1_b1'):
cl_abap_corresponding=>create(
source = struct2
destination = struct1
mapping = VALUE cl_abap_corresponding=>mapping_table(
( level = 0 kind = 1 srcname = 'bsub1-s1_b1' dstname = 'a1' ) )
)->execute( EXPORTING source = struct2
CHANGING destination = struct1 ).
What seems to be still impossible is to use the component selector in the DSTNAME component, e.g. the second execution cannot indicate destination = struct1 and dstname = 'asub1-b1', an exception would occur.
I want to use lookup value in Power BI, I'm using the following expression:
Type_to_Freq = LOOKUPVALUE(PP_Freq[Estimate],PP_Freq[Type],"Private")
the problem is, I need to pull different values from the table depending the result of one filter in my page.
Can the third field of lookup value could be dynamic?
If one filter I choose "Private", obtain the result for this, and if I choose "Public", change the result of "Private" to "Public".
What do I need to change to use that expression?
Something like this should do the trick:
Measure :=
VAR Selection =
SELECTEDVALUE ( PP_Freq[Type] )
RETURN
IF (
NOT ( ISBLANK ( Selection ) ),
LOOKUPVALUE ( PP_Freq[Estimate], PP_Freq[Type], Selection ),
"Make A Slection"
)
I'm new in Lotus Notes programming and I need your advices and your help.
My main form contains a table with 8 rows and 2 columns. ( there are 16 cells ) Every each cell has a numeric field. My fields name are :
txt_n1 and txt_i1 ( for 1st row )
txt_n2 and txt_i2 ( for 2nd row )
....
txt_n8 and txt_i8 ( for 8th row )
What I want to do is:
I have a view called vwMarketing with just one column. I want this view to display only those docs. in which there is at least one or more rows which its cells contains equal values.
So, if let say txt_n4 = txt_i4 => OK
row(k) (where k=1..8) : if cell 1 value is 5 and cell 2 value is 5 => OK.
There could be more than one row with this property, important is to exist at least one, and the values not to be null.
I hoped i was pretty clear, thanks !
PS: Actually, the formula statement i want to be in the column, so if it is OK => "A" and if not => "" ( in the view property, I checked : Don't show empty categories )
if you have small amount of documents in the view, then as u were suggested use Selection Formula to exclude documents with wrong condition.
you can add computed item/flag into your documents, field will compute if the document should be displayed in the view or not. then you will not have performance issue. i.e.
but code you need should look like that (that will check if documents is fine to be displayed in view or not), if you use it in view - just put after all Select _res = 1 otherwise if you decide to use flag into document (to increase performance) then Select youritem = 1
_res := 0;
#For(i:=1;i<=8;i:=i+1;
_post := #Text(i);
_txt_n := #GetField("txt_n"+_post);
_txt_i := #Text(#GetField("txt_i"+_post));
#If( (_txt_n=_txt_i) & (_txt_n!="");
#Do( _res := 1; i:=9);
0
)
);
_res
I would solve it slightly different:
Create a hidden text field on your form called 'DisplayInView' (or similar).
Modify the view selection: SELECT DisplayInView="Yes"
Add the code below to the PostSave event of your form:
Dim thisdoc As NotesDocument
Dim isSame As Boolean
isSame = False
Set thisdoc = source.Document
'*** Loop through all fields in document and compare the field pairs
Forall i In thisdoc.Items
If Left(i.Name,5) = "txt_n" Then
If i.Text = thisdoc.GetItemValue( Replace(i.Name,"txt_n","txt_i") )(0) Then
isSame = True
Exit Forall
End If
End If
End Forall
If isSame Then
Call doc.ReplaceItemValue("DisplayInView","Yes")
Call doc.Save(True,False)
End If
I haven't tested it, but I believe it should work.
Given XML file-record like this
<ADR-NSBG>
<timeline timestamp="2011-06-09T00:15:00">
<datum datum="SGC_at_bsNo-14___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4314320</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9040481</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2321242</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9136608</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>4643002</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1027420</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3433875</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>1845750</sbgSipOutgoingProvisionalResponses>
</datum>
<datum datum="SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4799739</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9335965</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2415690</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9474295</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>5291708</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1149950</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3516298</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>2190601</sbgSipOutgoingProvisionalResponses>
</datum>
</timeline>
</ADR-NSBG>
What I would like to do is to get the values of the children of the datum element.
so, I have written the following query:
for $i in collection("/db/_DEMO/ADR-NSBG/sipTransactTM/2011/06/09")
let $TIME_FROM := "2011-06-09T00:15:00"
let $TIME_TO := "2011-06-09T00:45:00"
let $DATUM := "SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2"
where ( $i/ADR-NSBG/timeline/#timestamp/string(.) >= $TIME_FROM and
$i/ADR-NSBG/timeline/#timestamp/string(.) <= $TIME_TO) and
( $i/ADR-NSBG/timeline/datum/#datum/string(.) = $DATUM )
order by $i/ADR-NSBG/timeline/#timestamp/string(.)
return $i/ADR-NSBG/timeline/datum
But, the problem is that I cannot choose between the two "datum" nodes.
the result of the query is:
<datum datum="SGC_at_bsNo-14___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4314320</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9040481</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2321242</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9136608</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>4643002</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1027420</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3433875</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>1845750</sbgSipOutgoingProvisionalResponses>
</datum>
<datum datum="SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2">
<sbgSipTotalIncSipRequests>4799739</sbgSipTotalIncSipRequests>
<sbgSipTotalIncSipResponses>9335965</sbgSipTotalIncSipResponses>
<sbgSipTotalIncFailureResponses>2415690</sbgSipTotalIncFailureResponses>
<sbgSipTotalOutSipRequests>9474295</sbgSipTotalOutSipRequests>
<sbgSipTotalOutSipResponses>5291708</sbgSipTotalOutSipResponses>
<sbgSipTotalOutFailureResponses>1149950</sbgSipTotalOutFailureResponses>
<sbgSipIncommingProvisionalResponses>3516298</sbgSipIncommingProvisionalResponses>
<sbgSipOutgoingProvisionalResponses>2190601</sbgSipOutgoingProvisionalResponses>
</datum>
What I would like to ask you is : Why the statement ( $i/ADR-NSBG/timeline/datum/#datum/string(.) = $DATUM ) does not work ?
Whithin the where clause you are filtering the $i elements of the for clause by using the datum element. You are not filtering the datum elements.
This expression:
( $i/ADR-NSBG/timeline/datum/#datum/string(.) = $DATUM )
is resolved to:
(
"SGC_at_bsNo-14___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2",
"SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2"
) =
"SGC_at_bsNo-13___SignalingNetworkConnection_at_netId-4___Sip_at_networkRole-2"
which is true. Therefore, the $i element is selected. After that, the expression in the return clause selects both child elements of the contained timeline element:
$i/ADR-NSBG/timeline/datum
How to filter the datum elements
If you want to select only the datum with a specific string, you need to filter in the return clause:
$i/ADR-NSBG/timeline/datum[#datum eq $DATUM]