How do I split multiple times in abap? - abap

I want to split my code into a workarea and append this to a an internal table for a later perform.
But sometimes the text contains more than 3 numbers for example 3;5;3;6;2;5 but its always 3,6,9,12... number. How can I solve the problem that I want to loop 3 times, then the next 3 numbers and so on?
DATA: text(100) type c,
it_1 TYPE STANDART TABLE LIKE text,
it_2 TYPE STANDART TABLE LIKE text,
it_3 TYPE STANDART TABLE LIKE text,
string(100) TYPE c.
text = '123;2;2'.
SPLIT text AT ';' INTO wa_1-c1 wa_1-c2 wa_1-c3.
APPEND wa_1-c1 to it_1.
APPEND wa_1-c2 to it_2.
APPEND wa_1-c3 to it_3.
LOOP at it_1 INTO string.
PERFORM task using string.
ENDLOOP.

You should use the INTO TABLE addition to the split keyword rather than hard coding the fields.
DATA: text_s TYPE string.
text_s = '123;2;2'.
DATA: text_tab TYPE TABLE OF string.
SPLIT text_s AT ';' INTO TABLE text_tab.
LOOP AT text_tab ASSIGNING FIELD-SYMBOL(<line>).
"do whatever on each token here
ENDLOOP.

This will split the string in 3-er blocks, while overwriting it with the rest:
WHILE text IS NOT INITIAL.
SPLIT AT ';'
INTO wa_1-c1
wa_1-c2
wa_1-c3
text.
APPEND: wa_1-c1 to it_1,
wa_1-c2 to it_2,
wa_1-c3 to it_3.
ENDWHILE.
Please note, the string variable text will be initial at the end, if its original value is still needed, than you can define another string, copy the value and use that one for the split.

You can try using Sy-tabix if you want to control the iterations three times and since you are saving the text values in 3 different internal tables.
DATA: text(100) type c,
it_1 TYPE STANDARD TABLE OF text,
it_2 TYPE STANDARD TABLE OF text,
it_3 TYPE STANDARD TABLE OF text,
string(100) TYPE c.
text = '123;2;2'.
SPLIT text AT ';' INTO TABLE it_1.
LOOP at it_1 INTO string WHERE sy-tabix = 3.
WRITE : string.
ENDLOOP.
if sy-tabix = 3.
LOOP AT it_2 INTO string WHERE sy-tabix = sy-tabix+3.
"do the next loop
ENDLOOP.
ENDIF.

Related

How to put column name in ALV Display

I have a definition like this:
TYPES: BEGIN OF ty_workarea,
data1 TYPE string,
data2 TYPE string,
data3 TYPE string,
END OF ty_workarea.
DATA gt_data TYPE TABLE OF ty_workarea.
Fields (data1, data2, data3) don't have any column name when I output it (gt_data) in ALV (cl_salv_table). How can I put name for them?
And since they have empty column names, I'm unable to do this trick:
lo_columns = go_alv->get_columns( ).
lo_column = lo_columns->get_column( 'CURRENT_NAME' ).
lo_column->set_long_text( 'NEW_NAME' ).
The get_column method expects the name of the field it represents, not the current heading text. So
lo_column = lo_columns->get_column( 'DATA1' ).
should get you the column you want.
Alternatively, the class CL_SALV_COLUMNS_TABLE (the one behind the lo_columns object) also has a method get which returns an internal table with the names and corresponding CL_SALV_COLUMN objects of all the columns. This can be useful in a context where you don't know the names of the columns you want to modify.
Columns names are taken by default from dict. You can try to use Sap elements or if you want to have custom title , you may define your own data element.
e.g use type MATNR instead of STRING for DataX and the title will be displayed for that column.

Casting of structure to string fails when structure contains a String field

I have a dynamic internal table <ft_dyn_tab>. I want to cast each row of the internal table to the type string via the field symbol <lf_string>:
LOOP AT <ft_dyn_tab> ASSIGNING <fs_dyn_wa>.
ASSIGN <fs_dyn_wa> to <lf_string> CASTING.
...
"other logic
...
ENDLOOP.
Normally, CASTING works fine when all fields of the structure are of type character. But when one field is of type string, it gives a runtime error. Can anyone explain why? And how to resolve this issue?
Why a structure with only character-like and String components can't be "casted" as a text variable
The reason is given by the ABAP documentation of Strings:
"A structure that contains a string is a deep structure and cannot be used as a character-like field in the same way as a flat structure.".
and of Deep:
"Deep: [...] the content [...] is addressed internally using references ([...], strings..."
and of Memory Requirement for Deep Data Objects:
"The memory requirement for the reference is 8 byte. [...] In strings, [...] an implicit reference is created internally."
and of ASSIGN - casting_spec:
"If the data type determined by CASTING is deep or if deep data objects are stored in the assigned memory area, the deep components must appear with exactly the same type and position in the assigned memory area. In particular, this means that individual reference variables can be assigned to only one field symbol that is typed as a reference variable by the same static type."
Now, the reason why the compiler and the run time don't let you do that, is that if you cast a whole deep structure, you could change the 8-bytes reference to access any place in the memory, that could be dangerous (How dangerous is it to access an array out of bounds?) and very difficult to analyze the subsequent bugs. In all programming languages, as far as possible, the compiler prevents out-of-bounds accesses or the checks are done at run time (Bounds checking).
Workaround
Your issue happens at run time because you use dynamically-created data objects, but you'd have exactly the same issue at compile time with statically-defined data objects. Below is a simple solution with a statically-defined structure.
You can access each field of the structure and concatenate it to a string:
DATA: BEGIN OF dyn_wa,
country TYPE c LENGTH 3,
city TYPE string,
END OF dyn_wa,
lf_string TYPE string.
FIELD-SYMBOLS: <lf_field> TYPE clike.
dyn_wa = VALUE #( country = 'FR' city = 'Paris' ).
DO.
ASSIGN COMPONENT sy-index OF STRUCTURE dyn_wa TO <lf_field>.
IF sy-subrc <> 0.
EXIT.
ENDIF.
CONCATENATE lf_string <lf_field> INTO lf_string RESPECTING BLANKS.
ENDDO.
ASSERT lf_string = 'FR Paris'. " one space because country is 3 characters
RESPECTING BLANKS keeps trailing spaces, to mimic ASSIGN ... CASTING.
Sounds like you want to assign the complete structured row to a plain string field symbol. This doesn't work. You can only assign the individual type-compatible components of the structured row to the string field symbol.
Otherwise, this kind of assignment works fine. For a table with a single column with type string:
TYPES table_type TYPE STANDARD TABLE OF string WITH EMPTY KEY.
DATA(filled_table) = VALUE table_type( ( `Test` ) ).
ASSIGN filled_table TO FIELD-SYMBOL(<dynamic_table>).
FIELD-SYMBOLS <string> TYPE string.
LOOP AT <dynamic_table> ASSIGNING FIELD-SYMBOL(<row>).
ASSIGN <row> TO FIELD-SYMBOL(<string>).
ENDLOOP.
For a table with a structured row type:
TYPES:
BEGIN OF row_type,
some_character_field TYPE char80,
the_string_field TYPE string,
END OF row_type.
TYPES table_type TYPE STANDARD TABLE OF row_type WITH EMPTY KEY.
DATA(filled_table) = VALUE table_type( ( some_character_field = 'ABC'
the_string_field = `Test` ) ).
ASSIGN filled_table TO FIELD-SYMBOL(<dynamic_table>).
FIELD-SYMBOLS <string> TYPE string.
LOOP AT <dynamic_table> ASSIGNING FIELD-SYMBOL(<row>).
ASSIGN <row>-the_string_field TO <string>.
ENDLOOP.
I have just tested this and it gives runtime error also when the structure does not have any string typed field.
I change the ASSIGN to a simple MOVE to a string variable g_string and it fails with runtime. If this fail it means that such an assignment is not possible, so the casting will not be either.
REPORT ZZZ.
TYPES BEGIN OF t_test.
TYPES: f1 TYPE c LENGTH 2,
f2 TYPE n LENGTH 4,
f3 TYPE string.
TYPEs END OF t_test.
TYPES BEGIN OF t_test2.
TYPES: f1 TYPE c LENGTH 2,
f2 TYPE n LENGTH 4,
f3 TYPE c LENGTH 80.
TYPES END OF t_test2.
TYPES: tt_test TYPE STANDARD TABLE OF t_test WITH EMPTY KEY,
tt_test2 TYPE STANDARD TABLE OF t_test2 WITH EMPTY KEY.
DATA(gt_test) = VALUE tt_test( ( f1 = '01' f2 = '1234' f3 = `Test`) ).
DATA(gt_test2) = VALUE tt_test2( ( f1 = '01' f2 = '1234' f3 = 'Test') ).
DATA: g_string TYPE string.
FIELD-SYMBOLS: <g_any_table> TYPE ANY TABLE,
<g_string> TYPE string.
ASSIGN gt_test2 TO <g_any_table>.
ASSERT <g_any_table> IS ASSIGNED.
LOOP AT <g_any_table> ASSIGNING FIELD-SYMBOL(<g_any_wa2>).
* ASSIGN <g_any_wa2> TO <g_string> CASTING.
g_string = <g_any_wa2>.
ENDLOOP.
UNASSIGN <g_any_table>.
ASSIGN gt_test TO <g_any_table>.
ASSERT <g_any_table> IS ASSIGNED.
LOOP AT <g_any_table> ASSIGNING FIELD-SYMBOL(<g_any_wa>).
* ASSIGN <g_any_wa> TO <g_string> CASTING.
g_string = <g_any_wa>.
ENDLOOP.

RTTI: Get length of a character column

My function module receives a table name and a column name at runtime.
I would like to get the length of the column: How many characters are allowed in the transparent table?
I used my favorite search engine and found RTTS.
But the examples in the documentation pass a variable to the RTTS method DESCRIBE_BY_DATA; in my case, I don't have a variable, I just have the type names in table_name and column_name.
How to get the length?
For retrieving the type of a given DDIC type only known at runtime, use the method DESCRIBE_BY_NAME. The RTTI length is always returned as a number of bytes.
Example to get the type of the column CARRID of table SFLIGHT (I know it's a column of 3 characters) :
cl_abap_typedescr=>describe_by_name(
EXPORTING
p_name = 'SFLIGHT-CARRID'
RECEIVING
p_descr_ref = DATA(lo_typedescr)
EXCEPTIONS
type_not_found = 1 ).
" you should handle the error if SY-SUBRC <> 0
" Because it's SFLIGHT-CARRID, I expect 6 BYTES
ASSERT lo_typedescr->length = 6. " 3 characters * 2 bytes (Unicode)
" Length in CHARACTERS
CASE lo_typedescr->type_kind.
WHEN lo_typedescr->typekind_char
OR lo_typedescr->typekind_num
OR lo_typedescr->typekind_date
OR lo_typedescr->typekind_time
OR lo_typedescr->typekind_string.
DATA(no_of_characters) = lo_typedescr->length / cl_abap_char_utilities=>charsize.
ASSERT no_of_characters = 3.
ENDCASE.
You don't need RTTS for this. You can Do one of this
Select table DD03L with TABNAME and FIELDNAME
Use Function DDIF_FIELDINFO_GET

converting input fields from text to columns in FoxPro or SQL

I have a set of input data in FoxPro. One of the fields, the grp field, is a concatenated string, the
individual portions of which are delimited by the pipe symbol, "|". Here are some examples of the values it can take:
grp:
ddd|1999|O|%
bce|%
aaa|2009|GON|Fixed|big|MAE|1
bbb|PAL|N|Fixed|MAE|1
aaa|SMK|O|Fixed|MAE|1|1
ddd|ERT|O|%
eef|%|N|%
afd|2000|O|%
afd|200907|O|%
swq|%|O|%
%
I would like to write a query that will separate the data above into separate fields and output them to another sql table, where the deciding factor for the separation is the pipe symbol. Taking the first two rows as an example, the output should read
Record 1:
Field1 = ddd Field2 = 1999 Field3 = O Field4 = %
Record 2:
Field1 = bce Field2 = % Field3 holds no value Field4 holds no value
It will not be known in advance what the greatest number of pipe symbols in the data will be. In the example above, it is 6, in records 3 and 5.
Is it actually possible to do this?
You can create a cursor and append the data into it using 'append from' (another way would be to use 2 alines, one for rows other for columns data). For example using your data as a text variable:
Local lcSample, lcTemp, lnFields, ix
TEXT to m.lcSample noshow
ddd|1999|O|%
bce|%
aaa|2009|GON|Fixed|big|MAE|1
bbb|PAL|N|Fixed|MAE|1
aaa|SMK|O|Fixed|MAE|1|1
ddd|ERT|O|%
eef|%|N|%
afd|2000|O|%
afd|200907|O|%
swq|%|O|%
%
ENDTEXT
lnFields = 0
Local Array laText[1]
For ix=1 To Alines(laText, m.lcSample)
m.lnFields = Max(m.lnFields, Occurs('|', m.laText[m.ix]))
Endfor
#Define MAXCHARS 20 && max field width expected
Local Array laField[m.lnFields,4]
For ix = 1 To m.lnFields
m.laField[m.ix,1] = 'F' + Ltrim(Str(m.ix))
m.laField[m.ix,2] = 'C'
m.laField[m.ix,3] = MAXCHARS
m.laField[m.ix,4] = 0
Endfor
lcTemp = Forcepath(Sys(2015)+'.txt', Sys(2023))
Strtofile(m.lcSample, m.lcTemp)
Create Cursor myData From Array laField
Append From (m.lcTemp) Delimited With "" With Character "|"
Erase (m.lcTemp)
Browse
However, in real world, this doesn't sound to be very realistic. You should know something about the data ahead.
And also, you could use FoxyClasses' import facilities to get the data. It lets you to choose the delimiters, map the columns etc. but requires some developer intervening for the final processing of the data.
The ALINES() function makes parsing easy. You could apply it to each line in turn. #Cetin has already showed you how to find out how many fields you need.
I had to do something very similar with some client data. They provided a field that was a space separated list of numbers that needed to be pulled out into a single column of numbers to match to an offer. Initially I dumped it to a text file, and imported it back into a new table. Something like the following:
create table groups ;
(group1 c(5), group2 c(5), group3 c(5), group4 c(5), group5 c(5))
select grp from infile to file grps.tmp noconsole plain
select groups
append from grps.tmp delimited with "" with character "|"

How do I split an ssrs text value by comma?

I have an SSRS report that takes a parameter called Customer ID Enroller List. Its datatype in SSMS is varchar(max) and its datatype in SSDT/SSRS is listed as text.
As an example, the user may pass in 2 customerID's like the following:
2110012639,2110179997
I'd like to create document map based the passed parameters but I need to split the values first. I've tried using the following code:
=Split(Parameters!CustomerID_EnrollerList.Value,",")
My report runs but the value returned in the textbox is #Error. Any ideas on how to split a text datatype parameter by a comma delimiter?
Split function returns an array and you can select item by its index
First value would be
=Split(Parameters!CustomerID_EnrollerList.Value,",")(0)
And Second value would be
=Split(Parameters!CustomerID_EnrollerList.Value,",")(1)