Inline Declarations - 内联声明

DATA(...) 内联声明方便了我们的使用,有了它我们在访问数据库的时候,直接写 SELECT 就可以了,不需要再去构建各式各样的內表和表类型了。在内表中它会自动根据读取的内表类型定义相应的工作区类型。但是使用这种方法注意作用域问题,它与普通定义的变量范围一致。

  • 注意在使用 FOR ALL ENTRIES 语句的时候,管理的内表前面要加上 @ @inner_table

  • 指针声明符:FIELD-SYMBOL(...)

Data statement

*Before 7.40
DATA text TYPE string.
text = 'ABC'.
*With 7.40
DATA(text) = 'ABC'. / DATA(lv_int) = 10.

Select into table

*Before 7.40
DATA itab TYPE TABLE OF mara.
DATA lv_matnr TYPE matnr.
SELECT * FROM mara INTO TABLE itab WHERE matnr = lv_matnr.
*With 7.40
SELECT * FROM mara INTO TABLE @DATA(gt_data)
SELECT mara~matnr,marc~werks
  FROM mara INNER JOIN marc ON mara~matnr = marc~matnr
  FOR ALL ENTRIES IN @itab
  WHERE mara~matnr = @itab-matnr
  INTO TABLE @DATA(gt_data).

Select single

*Before 7.40
SELECT SINGLE f1 f2 FROM scarr INTO (lv_f1, lv_f2) WHERE carrid = p_id.
*With 7.40
SELECT SINGLE f1 AS lv_f1, f2 AS lv_f2 
  FROM scarr INTO @DATA(wa) 
 WHERE carrid = @p_id.
WRITE: / wa-lv_f1, wa-lv_f2.

Loop at into work area

*Before 7.40
DATA wa like LINE OF itab. 
LOOP AT itab INTO wa. ... ENDLOOP.
*With 7.40
LOOP AT itab INTO DATA(wa). ... ENDLOOP.

Call method with parameter

*Before 7.40
DATA a1 TYPE char10.
DATA a2 TYPE char10.
oref->method( IMPORTING p1 = a1
              IMPORTING p2 = a2 ).
*With 7.40
oref->method( IMPORTING p1 = DATA(a1)
              IMPORTING p2 = DATA(a2) ). 

String Operation

CONCATENATE 'TEXT' '-' 'XXX' INTO DATA(str1).
SPLIT str1 AT '-' INTO DATA(part1) DATA(part2).
SPLIT str1 AT '-' INTO TABLE DATA(lt_parts).

Loop at assigning

*Before 7.40
FIELD-SYMBOLS: <line> type any.
LOOP AT itab ASSIGNING <line>. ... ENDLOOP.
*With 7.40
LOOP AT itab ASSIGNING FIELD-SYMBOL(<line>). ... ENDLOOP.

Read assigning

*Before 7.40
FIELD-SYMBOLS: <line> type any.
READ TABLE itab ASSIGNING <line>.
*With 7.40
READ TABLE itab ASSIGNING FIELD-SYMBOL(<line>).

内表操作

Table Expressions

itab [ ... ]相当于READ TABLE itab ...

如果对应条件没找到数据,会抛出 CX_SY_ITAB_LINE_NOT_FOUND 异常,系统变量 SY-SUBRC 不会记录成功与否。可使用 line_exists(itab[...]) 判断内表是否存在满足条件的数据 。

Read table index

*Before 7.40
READ TABLE itab INDEX idx INTO wa.
*With 7.40
DATA(wa) = itab[ idx ].

Read table using key

*Before 7.40
READ TABLE itab INTO wa INDEX idx USING KEY key.
*With 7.40
DATA(wa) = itab[ KEY key INDEX idx ].

Read table with key

*Before 7.40
READ TABLE itab INTO wa WITH KEY col1 = lv_col1 col2 = lv_col2.
*With 7.40
DATA(wa) = itab[ col1 = lv_col1 col2 = lv_col2 ].

Read table with key components

*Before 7.40
READ TABLE itab INTO wa WITH TABLE KEY key COMPONENTS col1 = lv_col1 
                                                      col2 = lv_col2 .
*With 7.40
DATA(wa) = itab[ KEY key col1 = lv_col1 col2 = lv_col2 ].

Does record exist

*Before 7.40
READ TABLE itab ... TRANSPORTING NO FIELDS. 
IF sy-subrc = 0. ...  ENDIF.
*With 7.40
IF line_exists( itab[  ] ). ... ENDIF. 

Get table index

*Before 7.40
DATA idx type sy-tabix. 
READ TABLE itab ... TRANSPORTING NO FIELDS.
IF sy-subrc = 0.
  idx = sy-tabix. 
ENDIF.
*With 7.40
DATA(idx) = line_index( itab[ ... ] ).

Value Operator Value - Value 作为赋值语句

新语法中,可以使用 VALUE 作为赋值语句,主要用来为内表、结构、变量等对象赋值。

在 VALUE 子句中,字段可以分开赋值,也可以使用结构整体赋值;为内表赋值时,需要用小括号将一行的数据包在一起。

Definition

Variables:VALUE dtype|# ( ). 构造一个任意类型的初始值。

Structures:VALUE dtype|# ( [BASE dobj] compl = a1 comp2 = a2 ... ).构造一个任意类型的结构体的初始值。

Tables:VALUE dtype|# ( [BASE itab] ( line1-com1 = dobj1 ) ( line2... ) ... ) 构造一个任意类型的内表的初始值。

  • dtype :想要转换成的类型(显式)

  • # :编译器必须使用上下文来决定要转换为的类型(隐式)

  • 如果 dtype 是个表,则必须指定 key 值,或者声明为 empty key

Example for structures

TYPES:BEGIN OF ty_columns1,   "Simple structure"
  cols1 TYPE i,
  cols2 TYPE i,
END OF ty_columns1.
TYPES: BEGIN OF ty_columns2, "Nested structure"
  coln1 TYPE i,
  coln2 TYPE ty_columns1,
END OF ty_columns2.
DATA:struc_nest TYPE ty_columns2.
struc_nest = VALUE ty_columns2( coln1 = 1 coln2-cols1 = 1 coln2-cols2 = 2 ).
"或则使用"
struc_nest = VALUE ty_columns2( coln1 = 1 coln2 = VALUE #( cols1 = 1 cols2 = 2 ) ).

Example for internal tables

  • 内表不能带表头
DATA itab TYPE TABLE OF i WITH EMPTY KEY.
*赋值
itab = VALUE #( ( 1 ) ( 2 ) ( 3 ) ).
*覆盖
itab = VALUE #( ( 4 ) ( 5 ) ( 6 ) ).
*追加
itab = VALUE #( BASE itab ( 1 ) ( 2 ) ( 3 ) ).
cl_demo_output=>display( itab ).
* Structured line type (RANGES table)
DATA rang_itab TYPE RANGE OF i.
rang_itab = VALUE #( 
              sign = 'I'  
              option = 'BT' ( low = 1  high = 10 )
                            ( low = 21 high = 30 )
                            ( low = 41 high = 50 )
              option = 'GE' ( low = 61 )  ).
cl_demo_output=>display( rang_itab ).

REF 定义引用变量

使用 REF 定义引用变量,用来代替 CREATE DATA。在使用 REF 时,不需要提前声明变量,也不用指定类型,类型默认会与被指向的变量保持一致。

TYPES: BEGIN OF str_mara,
    matnr TYPE mara-matnr,
    matar TYPE mara-matar,
    text1 TYPE char50,
  END OF str_mara.
DATA(ls_mara) = VALUE str_mara(
	matnr = 'material-001'
	matar = 'TYPE'
	text1 = 'test1' ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( ls_mara ).

DATA(lv_ref) = REF #( ls_mara ).
lv_ref->* = VALUE #(
      matnr = 'material-002'
      mtart = 'WATR' ).
lv_ref->text1 = 'test2'.
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( ls_mara ).

For operator

在内表赋值语句中,可以使用 FOR 语句从其他内表中批量引入数据并处理;可以认为是加强版的 LOOP AT 语句,与 REDUCE、VALUE 关键字配合使用。

  • 使用 FOR 语句时,需要为内表定义临时工作区,如 wa / <fs>,仅允许在当前语句中使用,赋值过程中会使用到该工作区。
  • 但在 WHERE 条件里,只能直接使用内表的字段名,需要注意的是,WHERE 后面接的条件语句必须使用小括号包起来。
  • INDEX INTO 定义的临时变量可用来记录当前操作行的序列,作用与 LOOP 语句中的系统变量 SY-TABIX 类似。

Definition

...FOR wa|<fs> IN itab [INDEX INTO idx] [COND].
...VALUE itab( FOR i = ... [THEN expr] UNTIL|WHERE log_ext ... )
...REDUCE dtype( INIT xxx FOR ... NEXT ... )

Examples

TYPES: BEGIN OF ty_ship,
  tknum TYPE tknum,     "Shipment Number"
  name  TYPE ernam,     "Name of Person who Created the Object"
  city  TYPE ort01,     "Starting city"
  route TYPE route,     "Shipment route"
END OF ty_ship.
TYPES: ty_ships TYPE SORTED TABLE OF ty_ship WITH UNIQUE KEY tknum.
TYPES: ty_citys TYPE STANDARD TABLE OF ort01. 

Example 1:用来自 GT_SHIPS 的 city 填充内部表 GT_CITYS。

*Before 7.40
DATA: gt_ships type ty_ships,
      gs_ship  TYPE ty_ship,
      gt_citys TYPE ty_citys,
      gs_city  TYPE ort01.
LOOP AT gt_ships INTO gs_ship.
  gs_city =  gs_shipcity.
  APPEND gs_city TO gt_citys.
  CLEAR:gs_city, gs_ship.
ENDLOOP.
*With 7.40
DATA(gt_citys) = VALUE ty_citys( FOR ls_ship IN gt_ships ( ls_ship-city ) ).
  • 注意:ls_ship 似乎尚未声明,但已隐式声明,作用范围在 VALUE ( ) 里面。

Example 2:使用来自 GT_SHIPS 且路线为 R0001 的 city 填充内部表 GT_CITYS。

*Before 7.40
DATA: gt_citys TYPE ty_citys,
      gs_ship  TYPE ty_ship,
      gs_city  TYPE ort01.
LOOP AT gt_ships INTO gs_ship WHERE route = R0001.
  gs_city =  gs_shipcity.
  APPEND gs_city TO gt_citys.
  CLEAR:gs_city, gs_ship.
ENDLOOP.
*With 7.40
DATA(gt_citys) = VALUE ty_citys( FOR ls_ship IN gt_ships 
                   WHERE ( route = 'R0001' ) ( ls_ship-city ) ).

FOR with THEN and UNTIL|WHILE

FOR i = … [THEN expr] UNTIL|WHILE log_exp

TYPES: BEGIN OF ty_line,
    col1 TYPE i,
    col2 TYPE i,
    col3 TYPE i,
  END OF ty_line,
  ty_tab TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
*Before 7.40
DATA: gt_itab TYPE ty_tab, 
      j TYPE i.
FIELD-SYMBOLS <ls_tab> TYPE ty_line.
j = 1.
DO.
  j = j + 10.
  IF j > 40. EXIT. ENDIF.
  APPEND INITIAL LINE TO gt_itab ASSIGNING <ls_tab>.
  <ls_tab>col1 = j.
  <ls_tab>col2 = j + 1.
  <ls_tab>col3 = j + 2.
ENDDO.
*With 7.40
DATA(gt_itab) = VALUE ty_tab( 
   FOR j = 11 THEN j + 10 UNTIL j > 40
     ( col1 = j col2 = j + 1 col3 = j + 2 ) 
).
cl_demo_output=>display( gt_itab ).

REDUCE 结合 FOR 使用

TYPES: BEGIN OF ty_result,
    sum   TYPE i,
    max   TYPE i,
    min   TYPE i,
    count TYPE i,
    avg   TYPE p DECIMALS 2,
  END OF ty_result.
DATA(result) = REDUCE ty_result( 
      INIT res = VALUE ty_result( max = 0 min = 99999 )
      FOR <fs> IN flights
      NEXT res-sum = res-sum + <fs>-distance
           res-count = res-count + 1
           res-max = nmax( val1 = res-max val2 = <fs>-distance )
           res-min = nmin( val1 = res-min val2 = <fs>-distance )
   ).
result-avg = result-sum / result-count.

Reduction operator - REDUCE

Definition

...REDUCE dtype(
  INIT result = start_value
  FOR for_exp1
  FOR for_exp2
  ...
  NEXT ...
       result = iterated_value
       ...
).

虽然 VALUE 和 NEW 表达式可以包含 FOR 表达式,但 REDUCE 必须包含至少一个 FOR 表达式。可以在 REDUCE 中使用各种 FOR 表达式

  • 使用 IN 迭代内部表
  • 使用 UNTIL 或 WHILE 进行条件迭代

Example

DATA gt_itab TYPE STANDARD TABLE OF i WITH EMPTY KEY.
gt_itab = VALUE #( FOR j = 1 WHILE j <= 10 ( j ) ).
* 7.40
DATA: lv_lines TYPE i,
      ls_itab TYPE i.
LOOP AT gt_itab INTO ls_itab.
  lv_lines = lv_lines + 1.
ENDLOOP.
*With 7.40
"统计行数"
DATA(lv_line) = REDUCE i( INIT x = 0 FOR wa IN gt_itab NEXT x = x + 1 ).
"求和"
DATA(lv_sum) = REDUCE i( INIT x = 0 FOR wa IN gt_itab NEXT x = x + wa ).

使用类引用

write 方法返回对实例对象的引用。

TYPES outref TYPE REF TO if_demo_output.
DATA(output) = REDUCE outref( INIT out  = cl_demo_output=>new( )
                                   text = `Count up:`
                              FOR n = 1 UNTIL n > 11
                              NEXT out = out->write( text )
                                   text = |{ n }| ).
output->display( ).

Move Corresponding Operator

MOVE-CORRESPONDING

Structures:MOVE-CORRESPONDING [EXACT] struc1 TO struc2 [EXPANDING NESTED TABLE].

Internal tables:MOVE-CORRESPONDING [EXACT] itab1 TO itab2 [EXPANDING NESTED TABLE] [KEPPING TARGET LINES].

Corresponding

语法:CORRESPONDING dtype|#( [BASE ( base )] struct|itab [mapping t1 = s1|except {t1 t2}] ).

  • MAPPING:允许使用名称不同的组件映射字段以符合数据传输的条件
  • EXCEPT:允许列出必须从数据传输中排除的字段

Example Code

*With 7.40
TYPES: BEGIN OF line1,
  col1 TYPE i,
  col2 TYPE i,
END OF line1.
TYPES: BEGIN OF line2,
  col1 TYPE i,
  col2 TYPE i,
  col3 TYPE i,
END OF line2.
DATA(ls_line1) = VALUE line1( col1 = 1 col2 = 2 ).
cl_demo_output=>display( ls_line1 ).
DATA(ls_line2) = VALUE line2( col1 = 4 col2 = 5 col3 = 6 ).
cl_demo_output=>display( ls_line2 ).
"CORRESPONDING"
ls_line2 = CORRESPONDING #( ls_line1 ).
cl_demo_output=>display( ls_line2 ).
"CORRESPONDING BASE"
"使用ls_line2的现有内容作为基础并被ls_line1中的匹配列覆盖"
ls_line2 = VALUE line2( col1 = 4 col2 = 5 col3 = 6 ).
ls_line2 = CORRESPONDING #( BASE ( ls_line2 ) ls_line1 ).
cl_demo_output=>display( ls_line2 ).
ls_line2 = VALUE line2( col1 = 4 col2 = 5 col3 = 6 ).
DATA(ls_line3) = CORRESPONDING line2( BASE ( ls_line2 ) ls_line1 ).
cl_demo_output=>display( ls_line3 ).
"MOVE-CORRESPONDING"
MOVE-CORRESPONDING ls_line2 TO ls_line3.
cl_demo_output=>display( ls_line3 ).

Filter

基于一个表中的记录过滤另一个表中的记录。

Definition

FILTER ptype|#( itab [EXCEPT] [IN ftab] [USING KEY keyname] WHERE c1 op f1 [AND c2 op f2 […]] )

  • EXCEPT:将返回完全相反的记录。

Template

TYPES: BEGIN OF ty_filter,
    cityfrom TYPE spflicityfrom,
    cityto   TYPE spflicityto,
    f3       TYPE i,
END OF ty_filter,
ty_filter_tab TYPE HASHED TABLE OF ty_filter WITH UNIQUE KEY cityfrom cityto.
DATA: lt_splfi TYPE STANDARD TABLE OF spfli.
SELECT * FROM spfli APPENDING TABLE lt_splfi.
DATA(lt_filter) = VALUE ty_filter_tab( f3 = 2
    ( cityfrom = NEW YORK  cityto  = SAN FRANCISCO )
    ( cityfrom = FRANKFURT cityto  = NEW YORK )  ).
DATA(lt_myrecs) = FILTER #( lt_splfi IN lt_filter
                  WHERE cityfrom = cityfrom 
                  AND cityto = cityto ).
Output filtered records
LOOP AT lt_myrecs ASSIGNING FIELDSYMBOL(<ls_rec>).
  WRITE: / <ls_rec>carrid,8 <ls_rec>cityfrom,30
           <ls_rec>cityto,45 <ls_rec>deptime.
ENDLOOP.