11-18-2008 2:15 PM
Hi all, first of all, sorry if this post may result "tricky", can't find a way to formulate it better...
I created an internal tab and wanted to manage in as a static (bidimensional) array. Fields of my table are labeled as follows:
||row_id| COL100 | COL101 | ... | COL 130 ||
,
where row_id type i and COLx type CHAR1.
I created an itab with, say, 100 rows (row_id, which is my key, goes for example from 141 to 240).
Well, I'd like to code this behaviour and ask you an hint/suggestion on how to do it:
"if a row Z has every COLx field marked with 'Y', then:
- shift down any row that precede (e.g., rows having row_id < row_id of row Z) row Z by 1.
Example: status of the table BEFORE condition evaluation:
||row_id|COL100|COL101|COL102|COL103|COL104||
-------------------------------------------------------------------------------------
|| 4 | O | Y | Y | O | O ||
|| 5 | Y | Y | O | O | O ||
|| 6 | O | Y | Y | O | Y ||
|| 7 | Y | Y | Y | Y | Y || "this is the line that satisfies the condition...
|| 8 | O | Y | Y | O | O ||
status of the table AFTER condition evaluation:
||row_id|COL100|COL101|COL102|COL103|COL104||
-------------------------------------------------------------------------------------
|| 4 | _ | _ | _ | _ | _ ||
|| 5 | O | Y | Y | O | O ||
|| 6 | Y | Y | O | O | O ||
|| 7 | O | Y | Y | O | Y ||row 7 has now same field values of the old row 6
|| 8 | O | Y | Y | O | O ||
I'm wondering if there's an easy way to do this; I can easy check for a "full line" LOOPing AT mytbl INTO wa_mytbl and comparing it with a full line (well, except for row_id, field by field). But then? I should loop in reverse order and copy the precedent row into the current one, till the top of the table is reached (and, of course, mantaining the row_id). Can anybody help me thinking a solution? Thanks in advance.
Edited by: Matteo Montalto on Nov 18, 2008 3:16 PM
11-18-2008 2:30 PM
You will not have to reverse loop to change value. Only 1 loop may suffice.
data : l_index type sy-tabix,
l_current type sy-tabix.
loop at itab.
l_index = sy-tabix.
l_current.
**if condition is satisfied
if l_index > 1. ** don't know what you will do if 1st row satisfies the condition
l_index = l_index - 1.
read table itab into wa_itab index l_index.
modify table itab from wa_itab index l_current..
delete itab index l_index.
endif.
endloop.
Regards,
Mohaiyuddin
11-18-2008 2:30 PM
You will not have to reverse loop to change value. Only 1 loop may suffice.
data : l_index type sy-tabix,
l_current type sy-tabix.
loop at itab.
l_index = sy-tabix.
l_current.
**if condition is satisfied
if l_index > 1. ** don't know what you will do if 1st row satisfies the condition
l_index = l_index - 1.
read table itab into wa_itab index l_index.
modify table itab from wa_itab index l_current..
delete itab index l_index.
endif.
endloop.
Regards,
Mohaiyuddin
11-18-2008 2:51 PM
Thanks Mohaiyuddin,
please forgive my bad english, probably I was not that clear in specifying that row_no IS a field of my table and should be kept, while the rest of the fields (COLx, when x is a number from 91 to 130) should be changed.
Also row_no is the key of my table and contains numbers from 10 to 39.
I didn't tried but seeing you used sy-tabix in the code I presume that this will erase completely the selected tuple and shift down the above ones. Right? Or I'm missing something?
EDIT: condition satisfied @ first row is avoided by other checks I implemented in my program, for what concerns the insertion in table.
EDIT 2: can't manage your code to work, probably because of my table hasn't an header line.
Edited by: Matteo Montalto on Nov 18, 2008 4:22 PM
11-19-2008 11:34 AM
That's getting more interesting. , sorry i didn't read complete question properly at first place.
Got an idea - Separate row_id and other field in 2 internal tables. perform operation on second internal table and merge both table [Bottom up].
data : begin of itab1 occurs 0,
row_id like itab-row_id,
end of itab1.
data : begin of itab2 occurs 0,
col1 like itab-col1,
.......colx like itab-colx,
end of itab2.
data : wa_itab like line of itab.
field-symbols : <f_itab> like line of itab,
<f_itab2> like line of itab2.
loop at itab assigning <f_itab>.
itab1-row_id - <f_itab>-row_id.
move-corresponding itab to itab2.
append : itab1, itab2.
endloop.
loop at itab2 assigning <f_itab2>.
**if condition is satisfied. (some routine to check coli = colx - this will be easy logic, hence not coding it here)
delete itab2.
clear wa_itab2.
insert wa_itab2 to itab2 index 1. " Append blank line
endif.
endloop.
refresh itab.
loop at itab1.
read table itab2 index sy-tabix.
if sy-subrc = 0.
wa_itab-row_id = itab1-row_id.
move-corresponding itab2 to wa_itab.
append wa_itab to itab.
clear wa_itab.
endif.
endloop.
I have typed code as logic only, not tested syntax. Please check syntax and apply appropriate change.
Logically it should give you desired result. Another way will be loop in loop, but above logic will be much faster than that.
Regards,
Mohaiyuddin
11-19-2008 11:58 AM
Hello Mohaiyuddin,
your hint is really interesting even tho I solved the prob in another way, the idea of grouping throu nested internal tables is something I will surely try in future. thx again!
11-18-2008 2:43 PM
I got exactly the same thought, it's not defined what you need to do if the condition checks in the first one.
I made this sample code with a limited IT to show how you can check easily if the condition checks.
DATA: BEGIN OF li_test,
row_id(3) TYPE n,
field1(1),
field2(1),
field3(1),
field4(1),
END OF li_test,
it_test LIKE TABLE OF li_test,
wa_test LIKE li_test.
INITIALIZATION.
wa_test-row_id = 1.
wa_test-field1 = 'Y'.
wa_test-field2 = 'O'.
wa_test-field3 = 'O'.
wa_test-field4 = 'Y'.
APPEND wa_test TO it_test.
wa_test-row_id = 2.
wa_test-field1 = 'Y'.
wa_test-field2 = 'Y'.
wa_test-field3 = 'O'.
wa_test-field4 = 'Y'.
APPEND wa_test TO it_test.
wa_test-row_id = 3.
wa_test-field1 = 'Y'.
wa_test-field2 = 'Y'.
wa_test-field3 = 'Y'.
wa_test-field4 = 'Y'.
APPEND wa_test TO it_test.
wa_test-row_id = 4.
wa_test-field1 = 'Y'.
wa_test-field2 = 'O'.
wa_test-field3 = 'O'.
wa_test-field4 = 'Y'.
APPEND wa_test TO it_test.
START-OF-SELECTION.
LOOP AT it_test INTO wa_test.
IF wa_test CO '1234567890Y'.
write wa_test-row_id.
ENDIF.
ENDLOOP.
11-18-2008 3:08 PM
IF wa_test CO '1234567890Y'.
It's quite OT w.r.t. my original post, anyway: I can't understand why that comparation string is satisfied by row3. ABAP Keyword Documentation doesn't help a lot understanding this.
11-18-2008 3:51 PM
I'll try to explain it.
When you refer to a structure using the main structure name and not the subfields, the result is a compact version of the whole record.
In the case of the third it looks like 003YYYY.
The IF has a CO (contains only) defined as 1234567890Y, meaning that only allows results that contain that characters and only that characters as true. Since all the other records contain also O they don't check. But since the third one is only composed of 0,3 and Y, it checks, as all are contained inside 1234567890Y.
11-18-2008 4:08 PM
Thanks Gustavo, it's clear now.
Any hint for the question "switch down the columns mantaining row_no field? 🐵
The code previously suggested by Mohaiyuddin doesn't do the trick, or better, doesn't work because of the fact it was written thinking I was working on a sorted/standard table... while I'm working on an internal table made as follows:
TYPES: BEGIN OF ty_cust_tbl,
rowno TYPE i,
col91 type CHAR1, col92 type CHAR1, col93 type CHAR1...
END OF ty_cust_tbl,
ty_tt_cust_tbl TYPE TABLE OF ty_cust_tbl.
DATA: tbl TYPE ty_tt_cust_tbl.
Now I'm able to identify the "filled" row easily; can't manage the "shift down" operation for all the colX fields. Please notice that ALL the lines above the 'filled' one should shift, not only the previous one.
11-18-2008 4:14 PM
11-18-2008 4:36 PM
Didn't understand the question, Gustavo. If you refer to the code posted above by Mohaiyuddin, it simply doesn't work (for the considerations I did before). Let's suppose that my table has 15 rows, and N columns: you mean, what happen to the first row if a "filled" line satisfying the condition is met?
Well, the fields of that line 1 will become the field of line 2 because of switching, while the first line will be set to be a "blank" line (e.g. all column fields containing 'O'). It's not a problem because the program allow to modify rows starting from the second row ot the table.
11-18-2008 6:08 PM
I hope this can resolve your problem. Sorry if i didn't understud your question.
DATA :
itab(10) OCCURS 0 WITH HEADER LINE,
wa_pre LIKE itab,
wa_act LIKE itab,
l_index TYPE sy-tabix.
LOOP AT itab.
IF itab = 'xx'. "This must be the condition to evaluate
l_index = sy-tabix.
This loop is to copy the first line in the second, the secont in the third, etc.
Also blanks the old first line
LOOP AT itab FROM 1 TO l_index.
IF sy-tabix = 1.
CLEAR wa_pre.
ELSE.
wa_act = itab.
itab = wa_pre.
MODIFY itab INDEX sy-tabix.
wa_pre = wa_act.
ENDIF.
ENDLOOP.
ENDIF.
ENDLOOP.
11-19-2008 9:12 AM
Thanks to you all for your help.
The problem is that the table I'm working on is a simple internal table (defined as I posted some post ago in this thread), so it's not a sorted table, neither a table with header line.
I tried to split the problem into sub-questions in order to solve this incrementally... Let's see.
1) find the row which has a line filled with Y.
This is the easiest job:
assuming that
DATA: current LIKE sy-tabix,
previous LIKE sy-tabix,
tbl TYPE ty_tt_mytbl,
wa_tbl TYPE ty_mytbl.
Then finding the "filled" row (can also be more than just one) is quite easy:
LOOP AT tbl INTO wa_tbl.
if wa_tbl CO '0123456789X'. "a line filled with marks
current = sy-tabix.
previous = current - 1.
EDIT: i found that the CO operator can be used only if the work area is declared with LIKE and a type available at dictionary. In my case it won't work, since wa_tbl is of TYPE ty_mytbl, which is a custom type def that is not a dictionary.
2) switch the lines, dropping down every line by 1, but MANTAINING the field row_no of every line.
In order to do this, I was thinking something like this (pseudocode):
while (current NE 1), do as follows:
save the row_no field of the current line in a temp variable, say 'tmp';
go to the 'previous' line;
move previous line into current line;
go to current line and set the row_no field = tmp.
current = current -1 and obviously, previous = previous - 1.
The problem is how to translate this pseudocode into abap code, taking into account that the table doesn't have an header line, and is defined in the way I wrote few posts ago.
As usual, thanks in advance.
Edited by: Matteo Montalto on Nov 19, 2008 10:31 AM
11-19-2008 10:19 AM
Hi Matteo
I've been following this thread with interest. One thought occurs to me. You're trying to emulate an array format, such as you'd find in Java. ABAP doesn't really support this very well, as you've found. What it does have is nested tables.
So you could have
Rowid | ColValues
-------------------
4 | O
| Y
| Y
| O
| O
-------------------
5 | Y
| Y
| O
| O
| O
...etc...
The code would then be:
REPORT.
TYPES: inner_ty TYPE STANDARD TABLE OF char1 WITH NON-UNIQUE KEY table_line,
BEGIN OF outer_ty,
rowid TYPE i,
t_inner TYPE inner_ty,
END OF outer_ty.
DATA: t_itab TYPE STANDARD TABLE OF outer_ty WITH NON-UNIQUE KEY rowid,
t_all_y TYPE inner_ty.
PERFORM populate_test_data.
PERFORM output_itab.
PERFORM do_processing.
PERFORM output_itab.
*................................
FORM populate_test_data .
DATA: ls_wa TYPE outer_ty.
ls_wa-rowid = 4.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
INSERT ls_wa INTO TABLE t_itab.
CLEAR ls_wa-t_inner.
ls_wa-rowid = 5.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
INSERT ls_wa INTO TABLE t_itab.
CLEAR ls_wa-t_inner.
ls_wa-rowid = 6.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
INSERT ls_wa INTO TABLE t_itab.
CLEAR ls_wa-t_inner.
ls_wa-rowid = 7.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
INSERT ls_wa INTO TABLE t_itab.
t_all_y = ls_wa-t_inner.
CLEAR ls_wa-t_inner.
ls_wa-rowid = 8.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'Y' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
APPEND 'O' TO ls_wa-t_inner.
INSERT ls_wa INTO TABLE t_itab.
ENDFORM. " populate_test_data
FORM output_itab.
DATA: ls_wa TYPE outer_ty,
l_in TYPE c LENGTH 1.
LOOP AT t_itab INTO ls_wa.
WRITE / ls_wa-rowid.
LOOP AT ls_wa-t_inner INTO l_in.
WRITE: l_in.
ENDLOOP.
ENDLOOP.
SKIP.
ENDFORM. "populate_test_data
FORM do_processing.
FIELD-SYMBOLS: <ls_wa> TYPE outer_ty.
DATA: ls_wa TYPE outer_ty,
l_hitcount TYPE i,
l_curr_rowid TYPE i.
SORT t_itab BY rowid DESCENDING.
LOOP AT t_itab ASSIGNING <ls_wa>.
l_curr_rowid = <ls_wa>-rowid.
IF <ls_wa>-t_inner EQ t_all_y.
ADD 1 TO l_hitcount.
DELETE t_itab.
ELSE.
ADD l_hitcount TO <ls_wa>-rowid.
ENDIF.
ENDLOOP.
* Add in blank records
DO 5 TIMES.
APPEND space TO ls_wa-t_inner.
APPEND space TO ls_wa-t_inner.
APPEND space TO ls_wa-t_inner.
APPEND space TO ls_wa-t_inner.
APPEND space TO ls_wa-t_inner.
ENDDO.
DO l_hitcount TIMES.
ls_wa-rowid = l_curr_rowid.
INSERT ls_wa INTO TABLE t_itab.
SUBTRACT 1 FROM l_curr_rowid.
ENDDO.
SORT t_itab BY rowid ASCENDING.
ENDFORM. "do_processing
If you can't change the table structure, for whatever reason, I think the algorithm in form "do_processing" should still be useful to you.
matt
11-19-2008 10:27 AM
Hi matt and thanks for your interest and hints,
well I know abap doesn't handle array structure... Nested table IS the solution, but everything I need to do can be done also with a single, internal table. And that's what I have to work with, because the rest of the code uses a table structured as I posted above; in order words, I can't manage to change the structure I'm working in. Anyway, I'm actually working on a form that makes that switch... I'll soon check if it works and post it again in this thread, also because I'd like to receive some suggestions on "how to do it better". Thanks for your contribute, tho.
11-19-2008 10:41 AM
It's nice to have posted here an interesting problem, for a change.
matt
11-19-2008 11:55 AM
Dear friends, got it
Well, at least it works even tho it's quite horrible 😛 I wonder if someone could help me cleaning up the code a bit: that's the form:
FORM check_lines CHANGING tbl TYPE ty_tt_mytbl.
DATA: current LIKE sy-tabix,
previous LIKE sy-tabix,
temp TYPE i,
wa_tbl TYPE ty_mytbl,
current_wa TYPE ty_mytbl,
wa_to_switch TYPE ty_mytbl.
LOOP AT tbl INTO wa_tbl.
if ( wa_tbl-col91 EQ 'X' AND wa_tbl-col92 EQ 'X' AND wa_tbl-col93 EQ 'X' AND wa_tbl-col94 EQ 'X' AND wa_tbl-col95 EQ 'X' AND
wa_tbl-col96 EQ 'X' AND wa_tbl-col97 EQ 'X' AND wa_tbl-col98 EQ 'X' AND wa_tbl-col99 EQ 'X' AND wa_tbl-col100 EQ 'X' AND
wa_tbl-col101 EQ 'X' AND wa_tbl-col102 EQ 'X' AND wa_tbl-col103 EQ 'X' AND wa_tbl-col104 EQ 'X' AND wa_tbl-col105 EQ 'X' AND
wa_tbl-col106 EQ 'X' AND wa_tbl-col107 EQ 'X' AND wa_tbl-col108 EQ 'X' AND wa_tbl-col109 EQ 'X' ). "a line filled with marks, except for what concerns the rowno field.
current = sy-tabix.
previous = current - 1.
WHILE current NE 5. "my limit in propagation of the switch procedure
READ TABLE tbl index current into current_wa.
temp = current_wa-rowno. "storing the row_number field.
READ TABLE tbl index previous into wa_to_switch.
wa_to_switch-rowno = temp.
MODIFY tbl INDEX current FROM wa_to_switch.
current = current - 1.
previous = previous - 1.
ENDWHILE.
ENDIF.
ENDLOOP.
ENDFORM.
Well, hope this could be helpful or at least interesting for someone else than me
The horrible part: IF condition. Can't manage a shorter and less "hardcorded" way to check for some field, I thought that relationals ops like CO could be applyable also to to work areas but I was wrong.
11-19-2008 12:10 PM
>
> The horrible part: IF condition. Can't manage a shorter and less "hardcorded" way to check for some field, I thought that relationals ops like CO could be applyable also to to work areas but I was wrong.
Please check if the following code helps, if it doesn't you can also check if the DO...VARYING construct
has something to offer
REPORT zytest.
TYPES:
BEGIN OF ty_cust_tbl,
rowno TYPE i,
col91 TYPE char1,
col92 TYPE char1,
col93 TYPE char1,
col94 TYPE char1,
END OF ty_cust_tbl,
BEGIN OF ty_col_cust_tbl,
col91 TYPE char1,
col92 TYPE char1,
col93 TYPE char1,
col94 TYPE char1,
END OF ty_col_cust_tbl,
ty_tt_cust_tbl TYPE TABLE OF ty_cust_tbl.
DATA:
tbl TYPE ty_tt_cust_tbl,
wa_col_tbl TYPE ty_col_cust_tbl,
wa_tbl LIKE LINE OF tbl,
wa_tbl_final LIKE LINE OF tbl,
tbl_final TYPE ty_tt_cust_tbl.
wa_tbl-rowno = 1.
wa_tbl-col91 = 'Y'.
wa_tbl-col92 = 'Y'.
wa_tbl-col93 = '0'.
wa_tbl-col94 = '0'.
APPEND wa_tbl TO tbl.
wa_tbl-rowno = 2.
wa_tbl-col91 = 'Y'.
wa_tbl-col92 = '0'.
wa_tbl-col93 = 'Y'.
wa_tbl-col94 = '0'.
APPEND wa_tbl TO tbl.
wa_tbl-rowno = 3.
wa_tbl-col91 = 'Y'.
wa_tbl-col92 = '0'.
wa_tbl-col93 = '0'.
wa_tbl-col94 = 'Y'.
APPEND wa_tbl TO tbl.
wa_tbl-rowno = 4.
wa_tbl-col91 = '0'.
wa_tbl-col92 = 'Y'.
wa_tbl-col93 = '0'.
wa_tbl-col94 = '0'.
APPEND wa_tbl TO tbl.
wa_tbl-rowno = 5.
wa_tbl-col91 = 'Y'.
wa_tbl-col92 = 'Y'.
wa_tbl-col93 = 'Y'.
wa_tbl-col94 = 'Y'.
APPEND wa_tbl TO tbl.
wa_tbl-rowno = 6.
wa_tbl-col91 = 'Y'.
wa_tbl-col92 = '0'.
wa_tbl-col93 = 'Y'.
wa_tbl-col94 = '0'.
APPEND wa_tbl TO tbl.
wa_tbl-rowno = 7.
wa_tbl-col91 = 'Y'.
wa_tbl-col92 = 'Y'.
wa_tbl-col93 = 'Y'.
wa_tbl-col94 = 'Y'.
APPEND wa_tbl TO tbl.
LOOP AT tbl INTO wa_tbl.
MOVE-CORRESPONDING wa_tbl TO wa_col_tbl.
IF wa_col_tbl CO 'Y'.
WRITE:/ 'Found'.
ENDIF.
ENDLOOP.
11-19-2008 1:09 PM
Rajesh said:
Please check if the following code helps, if it doesn't you can also check if the DO...VARYING construct has something to offer
IF wa_col_tbl CO 'Y'. WRITE:/ 'Found'.
Unfortunately, it doesn't. I noticed that it works only if the declaration part uses LIKE instead of TYPE (in such cases, the relational operator CO works even if the lvalue is actually a workarea). Hence I can't use it because my type is a custom one, can't use LIKE in DATA declaration with types that are not in dictionary.
11-19-2008 1:23 PM
One simple way.
Write a static functional method in an ABAP Class, which takes wa_tbl as its importing parameter, and returns 'X' if all the components are 'X'.
You could then write:
IF zcl_myclass=>my_method( wa_tbl ) IS NOT INITIAL.
instead of the horrible expression you currently have. Of course, this just shifts the expression into another place.
But then you've more room to play around with improving the expression inside the method. For example, you could use DO... VARYING... to skip from field to field. From the top of my head (i.e. no testing!), where i_wa is the importing parameter that holds the values in wa_tbl, and r_flag has value 'X' or space.
DATA: l_col TYPE i_wa-col91.
r_flag = 'X'.
DO 19 TIMES VARYING l_col FROM i_wa-col91 NEXT i_wa-col92.
IF l_col NE 'X'.
CLEAR r_flag.
EXIT.
ENDIF.
ENDDO.
Look at the VARYING keyword for details how to work it properly. I think, with ASSIGN, you can use it until you've used up all to "col" fields, so that could be dynamic also.
matt
11-19-2008 1:29 PM
>
>
Rajesh said:
> Please check if the following code helps, if it doesn't you can also check if the DO...VARYING construct has something to offer
>
IF wa_col_tbl CO 'Y'.
> WRITE:/ 'Found'.
>
> Unfortunately, it doesn't. I noticed that it works only if the declaration part uses LIKE instead of TYPE (in such cases, the relational operator CO works even if the lvalue is actually a workarea). Hence I can't use it because my type is a custom one, can't use LIKE in DATA declaration with types that are not in dictionary.
I've declared wa_col_tabl using the TYPE addition, isn't it? Anyways check the following logic,
hope it helps
DATA:
found type c value 'X',
char type c.
LOOP AT tbl INTO wa_tbl.
* MOVE-CORRESPONDING wa_tbl TO wa_col_tbl.
* IF wa_col_tbl CO 'Y'.
* WRITE:/ 'Found'.
* ENDIF.
DO 4 times VARYING char FROM wa_tbl-col91
NEXT wa_tbl-col92.
IF char NE 'Y'.
CLEAR found.
ENDIF.
ENDDO.
IF found = 'X'.
* processing.
ENDIF.
found = 'X'.
ENDLOOP.
Edited by: Rajesh on Nov 19, 2008 7:00 PM
OOPS, i'm late
11-19-2008 1:38 PM
11-19-2008 1:52 PM
>
> Only a little late. And you suggested DO... VARYING before me.
i'm glad to see you respond to my post :).
Many Thanks.