How to loop at a dynamic internal table? - abap

I'm working on an Enhancement Implantation on ZXMBCU10 which is called in a custom program couple of levels down the execution path. Inside ZXMBCU10 I want to access the a table in the parent program, which I do in the following method;
Declare the parent program name;
DATA: ex_tbl_name TYPE char100 VALUE '(ZPROGRAM)G_TAB'.
Getting the value through field symbol assignment.
FIELD-SYMBOLS: <fs> TYPE any.
ASSIGN (ex_tbl_name) TO <fs>.
Then I check for successful assignment (which is true).
IF <fs> IS ASSIGNED.
Problem I have is how to read the data in the <fs> field symbol.
I've tried LOOP and READ TABLE, but getting the following;
Both Read Table and Loop is added here just to get the syntax checks
LOOP;
Internal table "<FS>" has no header line - one of the additions "INTO
wa", "ASSIGNING", "REFERENCE INTO", "TRANSPORTING NO FIELDS" required.
required.
READ TABLE;
You cannot use explicit or implicit index operations on tables with
types "HASHED TABLE" or "ANY TABLE". "<FS>" has the type "ANY TABLE".
It is possible that the "TABLE" addition was not specified before
"<FS>".

LOOP AT
The error about LOOP AT (Internal table "<FS>" has no header line - one of the additions "INTO wa", "ASSIGNING", "REFERENCE INTO", "TRANSPORTING NO FIELDS" required), is that you don't indicate the "result" part of LOOP AT i.e. ASSIGNING, REFERENCE INTO... (as said in the message).
For a field symbol, LOOP AT alone is always invalid, and if it's a variable instead of a field symbol it's obsolete because that would imply the use of a header line.
LOOP AT <fs>. " always invalid !
A valid syntax could be as follows: you must declare the field symbol as being an internal table (with at least the word TABLE, or refer to a "Table Type"), any category of internal table is supported for LOOP AT (hashed, sorted, standard), so you can use TYPE ANY TABLE :
DATA: ex_tbl_name TYPE char100 VALUE '(ZPROGRAM)G_TAB'.
FIELD-SYMBOLS: <fs> TYPE ANY TABLE.
ASSIGN (ex_tbl_name) TO <fs>.
LOOP AT <fs> ASSIGNING FIELD-SYMBOL(<line>).
ENDLOOP.
READ TABLE
The error about READ TABLE (You cannot use explicit or implicit index operations on tables with types "HASHED TABLE" or "ANY TABLE". "<FS>" has the type "ANY TABLE". It is possible that the "TABLE" addition was not specified before "<FS>") is that you used READ TABLE ... INDEX ... whose INDEX means that it can only be used with an internal table with category SORTED or STANDARD.
The next code is invalid because of the combination of ANY TABLE and READ TABLE INDEX, because <FS> could eventually be a hashed internal table (who knows), then READ TABLE INDEX would fail, hence the compiler error:
DATA: ex_tbl_name TYPE char100 VALUE '(ZPROGRAM)G_TAB'.
FIELD-SYMBOLS: <fs> TYPE ANY TABLE. " <=== impossible with READ TABLE INDEX !
ASSIGN (ex_tbl_name) TO <fs>.
READ TABLE <fs> ASSIGNING FIELD-SYMBOL(<line>) INDEX 1. " <=== impossible with ANY TABLE !
Solution: to use READ TABLE <fs> INDEX ... you may declare the field-symbol as SORTED, STANDARD, or INDEX (the latter is a generic name corresponding to SORTED and STANDARD).
This code is valid:
DATA: ex_tbl_name TYPE char100 VALUE '(ZPROGRAM)G_TAB'.
FIELD-SYMBOLS: <fs> TYPE INDEX TABLE.
ASSIGN (ex_tbl_name) TO <fs>.
READ TABLE <fs> ASSIGNING FIELD-SYMBOL(<line>) INDEX 1.
Of course, it's assumed that G_TAB is an "index" table, not a hashed table!
PS: in your code you used INTO DATA(lv_fs) but usually if you have a generic internal table ASSIGNING is preferred.

change field symbol type to
any table.
instead of:
any.

Related

Binary search not working when looping on the same table

I'm making a function that exports a table with some data T_DATA[].
There is a part when I loop through an internal table( T_ENTRIES[]) and use binary search on the T_DATA[].
Before the Loop, T_DATA[] is sorted by the key I use in the read statement.
For some reason, the read fails a lot of time even if it has same key in both tables.
If i remove the binary search it works well.
Is this a common problem with tables that declared as exporting in the function?
Because when I move the table (T_DATA[]) to a different internal table and use the binary search on it, it works fine.
Thank you!
SORT t_patient_list[] BY kunnr.
LOOP AT lt_cov_entry[] ASSIGNING FIELD-SYMBOL(<ls_cov_entry>).
READ TABLE t_patient_list[]
ASSIGNING FIELD-SYMBOL(<fs_patient_list>)
WITH KEY kunnr = <ls_cov_entry>-kunnr.
BINARY SEARCH.
IF sy-subrc <> 0.
CLEAR ls_patient_record.
MOVE-CORRESPONDING <ls_cov_entry> TO ls_patient_record.
APPEND ls_patient_record TO t_patient_list[].
ELSE.
<fs_patient_list>-hosp_type = <ls_cov_entry>-hosp_type.
ENDIF.
ENDLOOP.
It does not work with BINARY SEARCH becuse the APPEND ruins the ordering. The best solution is to define t_patient_list as SORTED by kunnr. 1
If you cannot do that, you should use INSERT ... INDEX sy-tabix instead of APPEND, as even a failed READ TABLE sets it to the right value:
SORT t_patient_list[] BY kunnr.
LOOP AT lt_cov_entry[] ASSIGNING FIELD-SYMBOL(<ls_cov_entry>).
READ TABLE t_patient_list[]
ASSIGNING FIELD-SYMBOL(<fs_patient_list>)
WITH KEY kunnr = <ls_cov_entry>-kunnr
BINARY SEARCH.
IF sy-subrc <> 0.
CLEAR ls_patient_record.
MOVE-CORRESPONDING <ls_cov_entry> TO ls_patient_record.
INSERT ls_patient_record INTO t_patient_list[] INDEX sy-tabix.
ELSE.
<fs_patient_list>-hosp_type = <ls_cov_entry>-hosp_type.
ENDIF.
ENDLOOP.
1 ) If you can change it to SORTED, you still need to replace APPEND with INSERT, just without the INDEX part.
The problem is that you are appending to the table while you are reading it. After you append something, it might no longer be sorted, so BINARY SEARCH can no longer be expected to work reliably.
Possible workaround:
When the definition of the table t_patient_list is under your control, then add a secondary sorted table key to its declaration:
DATA t_patient_list TYPE TABLE OF patients
WITH NON-UNIQUE SORTED KEY key_kunnr COMPONENTS kunnr.
(you might use an even faster UNIQUE HASHED KEY when you can guarantee that kunnr includes only unique values)
Then explicitly use that key when searching:
READ TABLE t_patient_list[]
ASSIGNING FIELD-SYMBOL(<fs_patient_list>)
WITH TABLE KEY key_kunnr COMPONENTS kunnr = <ls_cov_entry>-kunnr.
(The addition BINARY SEARCH isn't required here because using a sorted key implies binary search).
Secondary keys are updated whenever the table is changed, so you can rely on them staying consistent.
More hackish workaround
When the definition of the table t_patient_list is not under your control, then you have to re-sort the table after changing it:
IF sy-subrc <> 0.
CLEAR ls_patient_record.
MOVE-CORRESPONDING <ls_cov_entry> TO ls_patient_record.
APPEND ls_patient_record TO t_patient_list[].
SORT t_patient_list[].
ELSE.
But you might want to measure if the performance penalty of sorting it after every append isn't more than you save by using BINARY SEARCH.

PROC SQL error: "ERROR: Expression using equals (=) has components that are of different data types."

I am trying to subset my data with PROC SQL, and it is giving me an error when I use my variable TNM_CLIN_STAGE_GROUP. Example below:
PROC SQL;
create table subset as
select ncdb.*
from ncdb
where YEAR_OF_DIAGNOSIS>2002
AND SEX = 2
AND LATERALITY IN (1,2,3)
AND HISTOLOGY = 8500
AND TNM_CLIN_STAGE_GROUP = 1;
quit;
ERROR: Expression using equals (=) has components that are of different data types.
When I run the same code, but take out the variable TNM_CLIN_STAGE_GROUP, the code works. Anyone know what the problem with that variable's name is?
That error indicates a difference in type. SAS has only two types, numeric and character, so the variable is probably character; verify the specific values, but in general it likely needs quotations (single or double, doesn't matter in this case).
If it is not a hardcoded value, but a value of another variable, you can use PUT to convert to character or INPUT to convert to numeric, whichever is easier to convert based on the data.
SAS in a data step will happily convert this for you, but in SQL and SQL-like (WHERE statements) it does not automatically convert character to numeric and vice versa; you must provide the correct type.
Before doing equality, check what you are trying to compare.
Check the structure of you ncbd table, in particulary field type of TNM_CLIN_STAGE_GROUP
You would see the real type, if its a varchar, you need to use single quote like #JChao suggest in is comment.
If its another type, so you need to adapt the comparator or use cast if you don t have choice.

How do you handle the values of the symbols in the symbol table?

In reference to chapter 6 of your book "Language Implementation Patterns"; what is the best practice/pattern for storing and retrieving values for each symbol.
Every symbol has a name, a type and a scope. However; where do you store the actual value?
I.e. symbol "n" of type "integer" has a value of 42.
What the symbol contains and how it contains that information is entirely your choice. In an untyped language the symbol could be just an object with term name and value attributes. For typing, add type and kind attributes.
Or the symbol object could contain just name and reference attributes, where the ref points into a separate table that contains additional attributes, including a reference that might point into a heap, immutables pool, or stack that actually stores the literal value.
This answer provides an example of a scoped, name and value symbol table.

Store ROWID in Oracle OBJECT type

I am trying the following:
CREATE TYPE T_TEST AS OBJECT (
TEST_ROWID ROWID,
TEST_DATA NUMBER(12)
);
/
But I get an error:
ORA-24344: success with compilation error
PLS-00530: Illegal type used for object type attribute: 'ROWID'.
I want to store the rowid's because they are faster than index lookups.
What is a good way for achieving the above? Casting to and from VARCHAR2 will probably introduce as much overhead as using the index?
There are at least two errors in your type definition.
Nonquoted identifiers cannot be Oracle SQL reserved words. Quoted identifiers can be reserved words, although this is not recommended.
Note: The reserved word ROWID is an exception to this rule. You cannot
use the uppercase word ROWID, either quoted or nonquoted, as a column
name. However, you can use the uppercase word as a quoted identifier
that is not a column name, and you can use the word with one or more
lowercase letters (for example, "Rowid" or "rowid") as any quoted
identifier, including a column name.
So you cannot use ROWID as the variable name.
The second one is that you cannot use ROWID type. If you try you'll get PLS-00530
As I know there are CHARTOROWID / ROWIDTOCHAR functions which may help.

Internal tables declaration in ABAP

I just started learning ABAP and I came acroos some different ways of declaring internal tables but I don't understand the difference between these ways. Which one is the best way?
Sample 1
types: begin of ty_tab,
field1,
field 2,
end of ty_tab.
data x_tab type ty_tab.
data itab like standard table of x_Tab.
Sample 2
types: begin of ty_tab,
field1,
field2,
end of ty_tab.
types x_tab type standard table of ty_tab.
data itab type x_tab.
Sample 3
data t_sflight type sflight.
Sample 1 first declares a type ty_tab with some fields. ty_tab is not a table type, it is a locally defined flat structure type. The data declaration following the type definition defines a local variable with name x_Tab and type ty_tab. The third data declaration then uses the "like" keyword to create a table that has lines "like" the structure x_Tab.
Sample 2 begins again with the definition of a type. But instead of first declaring a structure the data definition defines a standard table of type ty_tab.
Sample 3, as hennes mentioned in his comment, doesn't actually define a table. It defines a local structure based on a structure or table defined in the SAP Data Dictionary, in this case the transparent table "sflight". If you wanted to create an internal standard table based on DDIC table sflight, you would have to change the statement to:
data t_sflight type standard table of sflight.
All three variants are valid. Variant 1 and 2 create the identical (identical as in 'same fields, same properties') internal table with different means. There is no best way, each variant can be used where it fits. If you need a table that looks like one that already exists in the DDIC, use #3. #1 and #2 seem redundant at a glance, but sometimes you may receive a structure as a parameter and now want a internal table with that structure, so you can use the "like" keyword in #1.
Have a look at the SAP Help pages for more information.