ABAP S4新语法
ABAP S4新语法
FIELD-SYMBOL
ASSIGN COMPONENT L_I OF STRUCTURE WA1 TO FIELD-SYMBOL(<fs>).
ASSIGN LT_TAB[ 5 ] TO FIELD-SYMBOL(<fs>).
READ TABLE LT_TAB ASSIGNING FIELD-SYMBOL(<fs>) WITH KEY ZCHAR1 = '3'.
CONV
数据类型的转换可以用 CONV 实现,部分类型不再需要通过中间变量来转换
*---------------------------------------------------------------------*
* 合理的使用 CONV 可以避免因为类型不一致而导致的 dump 问题,
* 例如下例的LV_RESULT,即在调用方法时做参数的类型转换
* 另外,在接口中处理传入参数时,一般情况下也会对数据的类型做对应的转换,
* 但不是所有类型都可以互相转换,例如将含有非数字的 CHAR 类型数据
* 强制转换成 INT 类型时,会抛出异常CX_SY_CONVERSION_ERROR
*---------------------------------------------------------------------*
DATA(LV_STR) = '001001.001'.
DATA(LV_INT) = CONV I( LV_STR ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LV_INT ).
DATA(LV_FLOAT) = CONV F( LV_STR ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LV_FLOAT ).
DATA(LV_DIVISION) = 1 / 3.
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LV_DIVISION ).
DATA(LV_DIV) = CONV DECFLOAT34( 1 / 3 ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LV_DIV ).
字符拼接
*1. LV_STR1 = 'Hello World'.
DATA(LV_STR) = |Hello World|."这种语法限定了LV_STR的长度就是字符串的长度
*2. LV_STR1 = 'Hello World'.
DATA(LV_STR1) = |{ LV_STR }|.
*3. LV_STR1 = 'TOM,'.
LV_STR1 = |{ 'TOM,' }|.
*4. LV_STR1 = 'TOM,Hello World'.
LV_STR1 = LV_STR1 && LV_STR.
*5. 注意:Good后面的空格会被忽略,但是Morning前面的空格将被保留。LV_STR3 = 'Good Morning!'.
DATA(LV_STR3) = 'Good' && ' Morning!'.
*6. LV_STR4 = 'Hello World TOM,'
CONCATENATE LV_STR LV_STR1 INTO DATA(LV_STR4) SEPARATED BY SPACE.
SWITCH
动态赋值语句,通常根据同一变量的不同数据来动态处理,用法类似于 CASE 语句
*---------------------------------------------------------------------*
* SWITCH语句的判断条件相对单一,WHEN关键字后只能使用常量,
* THEN/ELSE后面可以使用表达式进行赋值
*---------------------------------------------------------------------*
DATA(LV_INDICATOR) = 1.
DATA(LV_DAY) = SWITCH CHAR10( LV_INDICATOR
WHEN 1 THEN 'MONDAY'
WHEN 2 THEN 'TUESDAY'
WHEN 3 THEN 'WEDNESDAY'
WHEN 4 THEN 'THURSDAY'
WHEN 5 THEN 'FRIDAY'
WHEN 6 THEN 'SATURDAY'
WHEN 7 THEN 'SUNDAY'
ELSE '404' && '-ERROR'
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LV_DAY ).
COND
动态赋值语句,可以根据不同条件来动态处理,用法类似于CASE/IF语句
*---------------------------------------------------------------------*
* COND语句中允许使用较为复杂的判断条件,因此VALUE语句中动态赋值通常会使用COND
*---------------------------------------------------------------------*
DATA(LV_INDICATOR) = 7.
DATA(LV_DAY) = COND CHAR10( WHEN LV_INDICATOR = 1 THEN 'MONDAY'
WHEN LV_INDICATOR = 2 THEN 'TUESDAY'
WHEN LV_INDICATOR = 3 THEN 'WEDNESDAY'
WHEN LV_INDICATOR = 4 THEN 'THURSDAY'
WHEN LV_INDICATOR = 5 THEN 'FRIDAY'
WHEN LV_INDICATOR = 6 THEN 'SATURDAY'
WHEN LV_INDICATOR = 7 AND SY-LANGU EQ 'E' THEN 'SUNDAY'
WHEN LV_INDICATOR = 7 AND SY-LANGU EQ 'F' THEN 'DIMANCHE'
WHEN LV_INDICATOR = 7 AND SY-LANGU EQ '1' THEN '星期天'
ELSE '404' && '-ERROR'
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LV_DAY ).
MOVE-CORRESPONDING(表或者字段之间赋值)
* MOVE-CORRESPONDING LT_TAB TO LT_TAB1.
* 相同字段名间赋值
LT_TAB1 = CORRESPONDING #( LT_TAB ).
CL_DEMO_OUTPUT=>DISPLAY( LT_TAB1 ).
* 不同字段名间赋值,使用关键字 MAPPING
DATA: BEGIN OF struct1,
mcomp1 TYPE i VALUE 1,
mcomp2 TYPE i VALUE 2,
BEGIN OF substruc,
subcomp1 TYPE i VALUE 1,
subcomp2 TYPE i VALUE 2,
subcomp3 TYPE i VALUE 3,
END OF substruc,
END OF struct1.
DATA: BEGIN OF struct2,
comp2 TYPE i,
comp1 TYPE i,
BEGIN OF substruc,
comp3 TYPE i,
comp2 TYPE i,
comp1 TYPE i,
END OF substruc,
END OF struct2.
struct2 =
CORRESPONDING #(
struct1 MAPPING comp1 = mcomp1
comp2 = mcomp2
( substruc = substruc MAPPING comp1 = subcomp1
comp2 = subcomp2
comp3 = subcomp3 ) ) .
VALUE
可以使用 VALUE 作为赋值语句,主要用来为内表、结构、变量等对象赋值
*---------------------------------------------------------------------*
* 参数类型引用同NEW关键字,在VALUE子句中,字段可以分开赋值,
* 也可以使用结构整体赋值,为内表赋值时,
* 需要用小括号将一行的数据包在一起
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_MARA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_MARA.
DATA: LT_MARA TYPE TABLE OF TY_MARA.
DATA(LW_MARA) = VALUE TY_MARA( MATNR = 'MATERIAL-001'
MTART = 'FOOD'
MATKL = '1020'
TEXT1 = 'FIRST material').
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LW_MARA ).
LT_MARA = VALUE #( ( LW_MARA )
( MATNR = 'MATERIAL-002'
MTART = 'FOOD'
MATKL = '1020'
TEXT1 = 'SECOND material')
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_MARA ).
*---------------------------------------------------------------------*
* 此外,VALUE语句作为结构时,可以直接在特定语句中使用
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
CHECKBOX TYPE C,
VALUE(4) TYPE C,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
APPEND VALUE #( VALUE = 'TEST' ) TO LT_DATA.
MODIFY LT_DATA FROM VALUE #( CHECKBOX = 'X' ) TRANSPORTING CHECKBOX WHERE CHECKBOX IS INITIAL.
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_DATA ).
BASE
在使用 VALUE 作为赋值语句时,默认会覆盖原有的数据,通过BASE子句基于原有数据进行赋值
注意: 使用 BASE 语句时,尽量保持前后结构一致,在使用不同的结构时,可能不报错但数据会错位
*---------------------------------------------------------------------*
* 在结构赋值语句中使用 BASE 时,原有字段的数据会被保留,
* 但是当在VALUE语句中对同一字段再次赋值时,该字段数据会被覆盖
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_MARA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_MARA.
DATA(LW_MARA) = VALUE TY_MARA( MATNR = 'MATERIAL-001'
MTART = 'FOOD' ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LW_MARA ).
LW_MARA = VALUE #( BASE LW_MARA
MTART = 'WATR'
MATKL = '1020'
TEXT1 = 'FIRST material').
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LW_MARA ).
*---------------------------------------------------------------------*
* 在内表赋值语句中使用 BASE 时,内表原有的数据会被保留,
* 新增条目会被追加到内表中,效果同 Append Line
*---------------------------------------------------------------------*
DATA LT_MARA TYPE TABLE OF TY_MARA.
LT_MARA = VALUE #( ( LW_MARA ) ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_MARA ).
LT_MARA = VALUE #( BASE LT_MARA
( MATNR = 'MATERIAL-002'
MTART = 'FOOD'
MATKL = '1030'
TEXT1 = 'SECOND material' )
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_MARA ).
FOR 写法及相关应用
在内表赋值语句中,可以使用FOR语句从其他内表中批量引入数据并处理
*&---------------------------------------------------------------------*
*& Report ZHCXTEST001
*&---------------------------------------------------------------------*
*&
*&---------------------------------------------------------------------*
REPORT ZHCXTEST001.
TYPES:
BEGIN OF LINE,
COL1 TYPE I,
COL2 TYPE I,
COL3 TYPE I,
END OF LINE,
ITAB TYPE STANDARD TABLE OF LINE WITH EMPTY KEY.
* 从1-10依次填充到表itab2中
DATA itab2 TYPE TABLE OF i WITH EMPTY KEY.
itab2 = VALUE #( FOR j = 1 WHILE j <= 10 ( j ) ).
cl_demo_output=>write( itab2 ).
DATA(ITAB) = VALUE ITAB(
* THEN J + 1 可缺省
FOR J = 11 THEN J + 1 UNTIL j > 12
( COL1 = J COL2 = J + 1 COL3 = J + 2 )
).
* 返回一个值
DATA(TOTAL) = REDUCE I( INIT RES = 0 FOR WA IN ITAB WHERE ( COL1 < 1000 ) NEXT RES = RES + WA-COL1 ).
* 返回一个结构
DATA(RESULT) = REDUCE LINE( INIT RES1 = VALUE LINE( COL2 = 0 COL3 = 9999999 )
FOR WA IN ITAB WHERE ( COL1 IS NOT INITIAL )
NEXT RES1-COL1 = RES1-COL1 + 1
* nmax|nmin( val1 = arg1 val2 = arg2 [val3 = arg3] ... [val9 = arg9] )
* 这些函数返回传递的最大或最小参数的值。必须至少传递两个参数 arg1 和 arg2,最多必须传递九个参数。
* 在这里,可选的输入参数 val3 到 val9 必须按升序填充,没有间隙。参数 arg1 到 arg9 是数值表达式位置。
RES1-COL2 = NMAX( VAL1 = RES1-COL1 VAL2 = WA-COL2 )
RES1-COL3 = NMIN( VAL1 = RES1-COL1 VAL2 = WA-COL3 )
).
CL_DEMO_OUTPUT=>DISPLAY( ITAB ).
CL_DEMO_OUTPUT=>DISPLAY( TOTAL ).
CL_DEMO_OUTPUT=>DISPLAY( RESULT ).
*---------------------------------------------------------------------*
* 使用FOR语句时,需要为内表定义临时工作区,如LWA_DATA,
* 仅允许在当前语句中使用,赋值过程中会使用到该工作区,
* 但在WHERE条件里,只能直接使用内表的字段名,需要注意的是,
*WHERE后面接的条件语句必须使用小括号包起来,INDEX INTO 定义的临时变量
*可用来记录当前操作行的序列,作用与LOOP语句中的系统变量 SY-TABIX 类似
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
TYPES: TY_TABLE TYPE TABLE OF TY_DATA WITH DEFAULT KEY.
LT_DATA = VALUE #(
( MATNR = 'MATRIAL-001'
MTART = 'WATR'
MATKL = '1020'
TEXT1 = 'FIRST material' )
( MATNR = 'MATRIAL-002'
MTART = 'FOOD'
MATKL = '1030'
TEXT1 = 'SECOND material' )
( MATNR = 'MATRIAL-003'
MTART = 'WATR'
MATKL = '1040'
TEXT1 = 'THIRD material' )
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_DATA ).
DATA(LT_FOR) = VALUE TY_TABLE(
FOR LW_DATA IN LT_DATA
INDEX INTO LV_INDEX
WHERE ( MTART = 'WATR' )
( MATNR = LW_DATA-MATNR
MTART = LW_DATA-MTART
MATKL = CONV #( LV_INDEX )
TEXT1 = LW_DATA-TEXT1 )
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_FOR ).
*---------------------------------------------------------------------*
* 在FOR语句中允许将结构作为整体直接进行赋值,但是结构必须与表行兼容,
* 可以用于从内表中获取特定条件的数据
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
TYPES: TY_TABLE TYPE TABLE OF TY_DATA WITH DEFAULT KEY.
LT_DATA = VALUE #(
( MATNR = 'MATRIAL-001'
MTART = 'WATR'
MATKL = '1020'
TEXT1 = 'FIRST material' )
( MATNR = 'MATRIAL-002'
MTART = 'FOOD'
MATKL = '1030'
TEXT1 = 'SECOND material' )
( MATNR = 'MATRIAL-003'
MTART = 'WATR'
MATKL = '1040'
TEXT1 = 'THIRD material' )
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_DATA ).
DATA(LT_FOR) = VALUE TY_TABLE(
FOR LW_DATA IN LT_DATA
WHERE ( MTART = 'WATR' )
( LW_DATA )
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_FOR ).
*---------------------------------------------------------------------*
* 如果结构与表行不兼容,可以嵌套使用CORRESPONDING语句进行赋值,
* 如下例( CORRESPONDING具体用法可参考后续示例 )
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
LT_DATA = VALUE #(
( MATNR = 'MATRIAL-001'
MTART = 'WATR'
MATKL = '1020'
TEXT1 = 'FIRST material' )
( MATNR = 'MATRIAL-002'
MTART = 'FOOD'
MATKL = '1030'
TEXT1 = 'SECOND material' )
( MATNR = 'MATRIAL-003'
MTART = 'WATR'
MATKL = '1040'
TEXT1 = 'THIRD material' )
).
TYPES: BEGIN OF TY_DATA_NEW,
MATNR TYPE MARA-MATNR,
MATKL TYPE MARA-MATKL,
END OF TY_DATA_NEW.
TYPES: TY_TABLE_NEW TYPE TABLE OF TY_DATA_NEW WITH DEFAULT KEY.
DATA(LT_FOR) = VALUE TY_TABLE_NEW(
FOR LW_DATA IN LT_DATA
WHERE ( MTART = 'WATR' )
( CORRESPONDING #( LW_DATA ) )
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_FOR ).
*---------------------------------------------------------------------*
* 结构字段过多时,一般建议使用整体赋值,如果少部分字段存在特殊的赋值逻辑
* 可嵌套使用VALUE以及BASE语句进行处理,将例1的逻辑转换如下:
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
TYPES: TY_TABLE TYPE TABLE OF TY_DATA WITH DEFAULT KEY.
LT_DATA = VALUE #(
( MATNR = 'MATRIAL-001'
MTART = 'WATR'
MATKL = '1020'
TEXT1 = 'FIRST material' )
( MATNR = 'MATRIAL-002'
MTART = 'FOOD'
MATKL = '1030'
TEXT1 = 'SECOND material' )
( MATNR = 'MATRIAL-003'
MTART = 'WATR'
MATKL = '1040'
TEXT1 = 'THIRD material' )
).
DATA(LT_FOR) = VALUE TY_TABLE(
FOR LW_DATA IN LT_DATA
INDEX INTO LV_INDEX
WHERE ( MTART = 'WATR' )
( VALUE #( BASE LW_DATA
MATKL = CONV #( LV_INDEX ) ) )
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_FOR ).
GROUP BY(FOR LOOP)
在 LOOP 语句中使用 GROUP BY 实现分组处理数据
*---------------------------------------------------------------------*
* 在 LOOP 中使用 GROUP BY 后,LWA_DATA 中不会存储相应的数据,同样,如果使用 FIELD-SYMBOL,
* 也不会被分配,如果需要修改内表数据,只能通过每个组进行修改,对内表数据进行分组时,
* 可通过 ASCENDING / DESCENDING 按组排序,否则按前后的顺序依次输出;
* GROUP BY 在需要使用多个字段进行分组时:GROUP BY ( KEY1 = field1 KEY2 = field2 … )
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
DATA LT_TABLE TYPE TABLE OF TY_DATA.
LT_DATA = VALUE #( ( MATNR = 'Material-001'
MTART = 'FOOD'
MATKL = '1020'
TEXT1 = 'FIRST' )
( MATNR = 'Material-002'
MTART = 'WATR'
MATKL = '1030'
TEXT1 = 'SECOND' )
( MATNR = 'Material-003'
MTART = 'WATR'
MATKL = '1020'
TEXT1 = 'THIRD' ) ).
LOOP AT LT_DATA INTO DATA(LWA_DATA) GROUP BY LWA_DATA-MATKL INTO DATA(G1).
LT_TABLE = VALUE #( FOR LWA_TABLE IN GROUP G1 ( LWA_TABLE ) ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_TABLE ).
ENDLOOP.
*---------------------------------------------------------------------*
* 如果需要根据自定义条件进行分组,可以使用 COND 语句将特定条件转换成字符或数字再进行分组
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
DATA LT_TABLE TYPE TABLE OF TY_DATA.
LT_DATA = VALUE #( ( MATNR = 'Material-001'
MTART = 'FOOD'
MATKL = '1020'
TEXT1 = 'FIRST' )
( MATNR = 'Material-002'
MTART = 'WATR'
MATKL = '1030'
TEXT1 = 'SECOND' )
( MATNR = 'Material-003'
MTART = 'WATR'
MATKL = '1010'
TEXT1 = 'THIRD' ) ).
LOOP AT LT_DATA INTO DATA(LWA_DATA)
GROUP BY COND STRING( WHEN LWA_DATA-MATKL = '1020' THEN 'A'
ELSE 'B' ) DESCENDING INTO DATA(G1).
LT_TABLE = VALUE #( FOR LWA_TABLE IN GROUP G1 ( LWA_TABLE ) ).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_TABLE ).
ENDLOOP.
*---------------------------------------------------------------------*
* 修改内表数据示例如下,第一层 LOOP 遍历的是每个组,
* 第二层遍历的是对应组里的数据,我们需要在第二层做变更
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
LT_DATA = VALUE #( ( MATNR = 'Material-001'
MATKL = '1020'
TEXT1 = 100 )
( MATNR = 'Material-002'
MATKL = '1030'
TEXT1 = 200 )
( MATNR = 'Material-003'
MATKL = '1020'
TEXT1 = 300 ) ).
LOOP AT LT_DATA INTO DATA(LWA_DATA) GROUP BY LWA_DATA-MATKL ASCENDING INTO DATA(G1).
DATA(LV_COUNT) = REDUCE #( INIT LV_INDEX = 0
FOR LWA_GROUP IN GROUP G1
NEXT LV_INDEX = LV_INDEX + LWA_GROUP-TEXT1 ).
LOOP AT GROUP G1 ASSIGNING FIELD-SYMBOL(<FS_LINE>).
<FS_LINE>-TEXT1 = LV_COUNT.
ENDLOOP.
ENDLOOP.
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_DATA ).
FILTER
使用 FILTER 根据条件来过滤内表数据
*---------------------------------------------------------------------*
* 使用 FILTER 时,待过滤的内表结构至少需要有一个用于访问的 SORTED KEY 或 HASHED KEY,
* 否则不能通过语法检查,另外,在 WHERE 条件中运算符两边的字段类型需要完全兼容,否则也不能通过语法检查;
* 根据条件进行过滤的功能可以使用 VALUE 嵌套 FOR 语句实现,而且不用考虑内表的键值问题
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA:LT_DATA TYPE TABLE OF TY_DATA WITH KEY MATNR WITH NON-UNIQUE SORTED KEY MATKL COMPONENTS MATKL.
LT_DATA = VALUE #( ( MATNR = 'Material-001'
MATKL = '1020'
TEXT1 = 100 )
( MATNR = 'Material-002'
MATKL = '1030'
TEXT1 = 200 )
( MATNR = 'Material-003'
MATKL = '1020'
TEXT1 = 300 ) ).
DATA(LT_FILTER) = FILTER #( LT_DATA USING KEY MATKL WHERE MATKL = CONV MATKL( '1020' ) )."CONV对值进行类型转换
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_FILTER ).
DATA(LT_FILTER2) = FILTER #( LT_DATA USING KEY MATKL WHERE MATKL > CONV MATKL( '1020' ) )."可以填入比较运算符
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LT_FILTER2 ).
*---------------------------------------------------------------------*
* 参照内表来过滤数据时,被参照的内表仍然需要有 SORTED KEY 或 HASHED KEY,对于过滤数据的内表没有键值要求;
* 在 FILTER 语句中可以通过 EXCEPT 关键字来指定是需要过滤数据还是保留数据;
* 该语法可以实现 FOR ALL ENTRIES IN,但是需要将数据全部取出,影响性能,
* 不建议使用,且在 ABAP 7.52 后,允许将内表作为数据源,可以用来代替 FOR ALL ENTRIES IN 使用
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA: LT_DATA TYPE SORTED TABLE OF TY_DATA WITH UNIQUE KEY MATNR,
LT_TEMP TYPE TABLE OF TY_DATA.
LT_DATA = VALUE #( ( MATNR = 'MATERIAL-001' MATKL = '1020' )
( MATNR = 'MATERIAL-002' MATKL = '1030' )
( MATNR = 'MATERIAL-003' MATKL = '1020' ) ).
LT_TEMP = VALUE #( ( MATNR = 'MATERIAL-002' MATKL = '1000' )
( MATNR = 'MATERIAL-002' MATKL = '1040' )
( MATNR = 'MATERIAL-004' MATKL = '1020' ) ).
DATA(LT_FILTER) = FILTER #( LT_TEMP IN LT_DATA WHERE MATNR = MATNR ).
DATA(LT_EXCEPT) = FILTER #( LT_TEMP EXCEPT IN LT_DATA WHERE MATNR = MATNR ).
EXACT
关键字 EXACT 可以用来检查操作语句返回值是否存在丢失,如果存在丢失则会抛出异常
*---------------------------------------------------------------------*
* 抛出异常的范围比CONV更广,例如将CHAR10的数据赋值到CHAR1时,
* 因此在使用时需要注意异常的捕获,如果没有特殊的处理或属性需求,
* 可以直接使用父类异常 CX_SY_CONVERSION_ERROR 进行捕获.
* 判断数值语句是否被精确计算,如下实际抛出的异常是CX_SY_CONVERSION_ROUNDING,
* 获取到该异常类中的属性字段VALUE的数据
*---------------------------------------------------------------------*
TRY .
DATA(LV_DATA) = EXACT #( 3 * ( 1 / 3 ) ).
CATCH CX_SY_CONVERSION_ROUNDING INTO DATA(LO_EXCEPT).
DATA(LV_RESULT) = LO_EXCEPT->VALUE.
ENDTRY.
*---------------------------------------------------------------------*
* 字段类型不兼容时,如下实际抛出的异常是 CX_SY_CONVERSION_NO_NUMBER,
* 这里获取的是父类CX_SY_CONVERSION_ERROR中的返回信息
*---------------------------------------------------------------------*
TYPES LTY_NUM TYPE N LENGTH 10.
TRY .
DATA(LV_NUM) = EXACT LTY_NUM( '4 Apples' ).
CATCH CX_SY_CONVERSION_ERROR INTO DATA(LO_CONVERT).
DATA(LV_ERROR) = LO_CONVERT->GET_TEXT( ).
ENDTRY.
LET
使用 LET 引入短生命周期变量,可以用来简化部分冗余代码
*---------------------------------------------------------------------*
* LET关键字可以使用在VALUE,SWITCH,COND等语句中;
* 与 FOR 语句类似,LET 语句中定义的临时变量同样只能在当前语句中使用,
* 在其他语句中使用时会检查出语法错误
*---------------------------------------------------------------------*
TYPES: BEGIN OF TY_DATA,
MATNR TYPE MARA-MATNR,
MTART TYPE MARA-MTART,
MATKL TYPE MARA-MATKL,
TEXT1 TYPE CHAR50,
END OF TY_DATA.
DATA LT_DATA TYPE TABLE OF TY_DATA.
LT_DATA = VALUE #(
( MATNR = 'MATRIAL-001'
MTART = 'WATR'
MATKL = '1020'
TEXT1 = 'FIRST material' )
( MATNR = 'MATRIAL-002'
MTART = 'FOOD'
MATKL = '1030'
TEXT1 = 'SECOND material' )
( MATNR = 'MATRIAL-003'
MTART = 'WATR'
MATKL = '1040'
TEXT1 = 'THIRD material' )
).
DATA(LW_LINE) = VALUE TY_DATA( LET
LW_DATA = VALUE #( LT_DATA[ MATNR = 'MATRIAL-001' ] OPTIONAL )
LV_STR = 'Date:' && SY-DATUM
IN
MATNR = LW_DATA-MATNR
MTART = LW_DATA-MTART
MATKL = LW_DATA-MATKL
TEXT1 = LV_STR
).
CALL METHOD CL_DEMO_OUTPUT=>DISPLAY( LW_LINE ).
去前导零 加前导零
旧语法:
去字符串前导0:CONVERSION_EXIT_ALPHA_OUTPUT
加字符串前导0:CONVERSION_EXIT_ALPHA_INPUT
S4新语法:
去X的前导零:X = |{ X ALPHA = OUT }|
加X的前导零:X = |{ X ALPHA = IN }|
内表itab
IF line_exists( lt_auth_attach[ 1 ] ).
****
ENDIF.
内表追加数据
内表操作指定行赋值(不会改变系统变量SY-TABIX的值)
DATA(WA1) = LT_TAB[ 5 ].
CL_DEMO_OUTPUT=>DISPLAY( WA1 ).
变量类型转换
DATA(lv_task_id) = CONV ze_process_task_id( ls_data-task_id ).
DATA(LV_INT) = CONV i( '1' )
内表是否为空
IF NOT line_exists( para[ 1 ] ).
RETURN.
ENDIF.
枚举ENUM
1.
TYPES:
BEGIN OF ENUM planet,
mercury,
venus,
earth,
mars,
jupiter,
saturn,
uranus,
neptune,
END OF ENUM planet.
DATA planet type planet.
planet = earth.
cl_demo_output=>display( planet ).
TYPES: BEGIN OF ENUM number, n0, n1 , n2 , n3, n4, n5, n6, n7, n8, n9, END OF ENUM number. DATA doma_values TYPE TABLE OF dd07v. CALL FUNCTION 'DD_DOMVALUES_GET' EXPORTING domname = 'S_NUMBERS' TABLES dd07v_tab = doma_values. TRY. LOOP AT doma_values INTO DATA(doma_value). DATA(number) = CONV number( CONV i( doma_value-domvalue_l ) ). WRITE: number. ENDLOOP. CATCH cx_sy_conversion_no_enum_value. cl_demo_output=>display( |{ doma_value-domvalue_l } does not match| ). ENDTRY.
TYPES: BEGIN OF ENUM planet STRUCTURE p, mercury, venus, earth, mars, jupiter, saturn, uranus, neptune, END OF ENUM planet STRUCTURE p. DATA planet type planet. planet = p-earth. cl_demo_output=>write( planet ). cl_demo_output=>display( p ).
MESH
TYPES:
tt_root TYPE HASHED TABLE OF zrre_s_bo_caseh_c WITH UNIQUE KEY key,
tt_cljg TYPE HASHED TABLE OF zrre_d_bo_casecl WITH UNIQUE KEY db_key
WITH NON-UNIQUE SORTED KEY key_par COMPONENTS parent_key,
tt_fcp TYPE HASHED TABLE OF zrre_d_bo_casefc WITH UNIQUE KEY db_key
WITH NON-UNIQUE SORTED KEY key_par COMPONENTS parent_key,
tt_seci TYPE HASHED TABLE OF zrre_d_bo_casesi WITH UNIQUE KEY db_key
WITH NON-UNIQUE SORTED KEY key_par COMPONENTS parent_key,
tt_retr TYPE HASHED TABLE OF zrre_d_bo_casert WITH UNIQUE KEY db_key
WITH NON-UNIQUE SORTED KEY key_par COMPONENTS parent_key,
BEGIN OF MESH ts_mesh,
root TYPE tt_root
ASSOCIATION _cljg TO cljg ON parent_key = key USING KEY key_par
ASSOCIATION _fcp TO fcp ON parent_key = key USING KEY key_par
ASSOCIATION _seci TO seci ON parent_key = key USING KEY key_par
ASSOCIATION _retr TO retr ON parent_key = key USING KEY key_par,
cljg TYPE tt_cljg,
fcp TYPE tt_fcp,
seci TYPE tt_seci,
retr TYPE tt_retr,
END OF MESH ts_mesh.
DATA ls_mesh TYPE ts_mesh.
SELECT FROM zrre_d_bo_caseh
FIELDS db_key AS key, ajlx, wfsf, ref_anyoui_ayno, pzrq, ajjb, bdje
WHERE ajzt NE @zrre_cl_ac_case_controller=>cs_ajzt-draft
AND appstatus = @/rer/if_ccm_constants=>gc_appstatus-approved
AND ajly NE @zrre_cl_ac_case_controller=>cs_ajly-from_sfsj
INTO CORRESPONDING FIELDS OF TABLE @ls_mesh-root.
CHECK sy-subrc EQ 0.
"FCP
SELECT FROM zrre_d_bo_casefc AS a INNER JOIN @ls_mesh-root AS b
ON a~parent_key = b~key
FIELDS a~*
INTO CORRESPONDING FIELDS OF TABLE @ls_mesh-fcp.
"CLJG
SELECT FROM zrre_d_bo_casecl AS a INNER JOIN @ls_mesh-root AS b
ON a~parent_key = b~key
FIELDS a~db_key, a~parent_key, a~ssfy, a~sfja, a~whss, a~jarq, a~jafs
INTO CORRESPONDING FIELDS OF TABLE @ls_mesh-cljg.
"SECI
SELECT FROM zrre_d_bo_casesi AS a INNER JOIN @ls_mesh-root AS b
ON a~parent_key = b~key
FIELDS a~db_key, a~parent_key, a~ssfy, a~sfja, a~whss, a~jarq, a~jafs
INTO CORRESPONDING FIELDS OF TABLE @ls_mesh-seci.
"RETR
SELECT FROM zrre_d_bo_casert AS a INNER JOIN @ls_mesh-root AS b
ON a~parent_key = b~key
FIELDS a~db_key, a~parent_key, a~ssfy, a~sfja, a~whss, a~jarq, a~jafs
INTO CORRESPONDING FIELDS OF TABLE @ls_mesh-retr.
LOOP AT ls_mesh-root ASSIGNING FIELD-SYMBOL(<fs_root>).
IF VALUE #( ls_mesh-root\_cljg[ <fs_root> ]-sfja OPTIONAL ) EQ abap_true
OR VALUE #( ls_mesh-root\_seci[ <fs_root> ]-sfja OPTIONAL ) EQ abap_true
OR VALUE #( ls_mesh-root\_retr[ <fs_root> ]-sfja OPTIONAL ) EQ abap_true.
ENDIF.
LOOP AT ls_mesh-root\_retr[ <fs_root> ] INTO DATA(ls_cljg).
ENDLOOP.
ENDLOOP.
WITH
Common Table Expressions (CTE)
SQL Enhancements:
- Higher expresiveness in Open SQL ABAP SQL statements, ABAP 7.53,>Open SQL已经被更名为ABAP SQL。这个重命名反映出ABAP SQL的某些部分目前只支持特定的数据库平台(SAP HANA数据库),已经不再是全平台独立的了。游标cursor和存储过程属于native SQL;
- Code pushdown through new language features
- Reduction of existing limitations
- Flexible consumption of CDS modeling entities
在from子句使用子查询;
" CTE, coalensce, max join 50, max sub_query 50;
DATA: lv_empty(8) TYPE c.
WITH +mara( matnr, ersda, nul ) AS
( SELECT matnr, ersda, lvorm FROM mara ), "UP TO 3 ROWS
+m2( matnr, coalesce ) AS
( SELECT matnr, @lv_empty AS coalesce FROM +mara )
SELECT FROM +mara AS mara LEFT OUTER JOIN +m2 AS m2 ON mara~matnr = m2~matnr
FIELDS mara~matnr,
coalesce( '截胡', “ 如果不为空则获取此变量并跳出coalesce,否则看下一个参数;
CASE m2~coalesce WHEN @lv_empty THEN mara~nul END, “如果为null则看下一个
m2~coalesce, “如果为空则看下一个
'coalesce' ) AS col2
INTO TABLE @DATA(lt_data6)
UP TO 8 ROWS
.
cl_demo_output=>display( lt_data6 ).
WITH
+cte_simple_tree_source AS
( SELECT FROM @__mt_tree_source AS tree_source
FIELDS id,
parent_id AS parent,
name )
WITH ASSOCIATIONS (
JOIN TO MANY +cte_simple_tree_source AS _tree
ON +cte_simple_tree_source~parent = _tree~id ),
+tree AS
( SELECT FROM HIERARCHY(
SOURCE +cte_simple_tree_source
CHILD TO PARENT ASSOCIATION _tree
START WHERE id = '0'
SIBLINGS ORDER BY id
MULTIPLE PARENTS NOT ALLOWED ) AS cte_hierarchy
FIELDS * )
WITH HIERARCHY cte_hierarchy
SELECT FROM +tree "hierarchy
FIELDS +tree~*,
hierarchy_rank,
hierarchy_tree_size,
hierarchy_parent_rank,
hierarchy_level,
hierarchy_is_cycle,
hierarchy_is_orphan,
node_id,
parent_id
INTO TABLE @DATA(lt_hierarchy).
ABAP SQL
Host Variable/Expression
在查询语句中使用 @ 作为转义符
通常在查询语句中,程序声明(非数据库层级)的变量前需要使用转义符 @ 进行标识,这些 Host Variable 通常被用作 Open SQL 语句中的操作数
在查询语句内部声明结构/内表时,应该在 DATA 前使用转义符
此外,在使用 Host Expression(在 Open SQL 中作为操作数使用的一些表达式) 时,也需要添加转义字符,如下例所示
(注:表达式内部的变量不需要再使用转义符,且不能使用表达式外部的数据库对象)
SELECT matnr,
@( COND #( WHEN sy-langu = 'E' THEN 'Material'
WHEN sy-langu = '1' THEN '物料' ) ) AS desc
FROM mara
INTO TABLE @DATA(lt_data)
UP TO @( CONV #( '005' ) ) ROWS.
SELECT matnr, maktx
FROM makt
WHERE spras = @sy-langu
AND matnr = @( VALUE #( lt_data[ 5 ]-matnr OPTIONAL ) )
INTO TABLE @DATA(lt_desc).
Typed Literals
(refer F1) 可以使用INTO table @DATA(lv_exist)新建变量接收数据,可以用类型文字语法在sql中新建all built-in ABAP Dictionary types常量;
SELECT *
FROM dbtab
WHERE char_col = char`hallo`
AND int_col = int8`123`
Built-In Functions
在 SELECT LIST 使用内嵌表达式来处理数值,使用时需注意传入参数的类型
DATA(lv_dec) = CONV zdec_3_demo( '-123.456' ).
SELECT SINGLE
@lv_dec AS original,
abs( @lv_dec ) AS abs,
ceil( @lv_dec ) AS ceil,
floor( @lv_dec ) AS floor,
div( -4 , -3 ) AS div,
division( -4 , -3 , 2 ) AS division,
mod( -4 , -3 ) AS mod,
round( @lv_dec , 2 ) AS round_po,
round( @lv_dec , -2 ) AS round_ne
FROM sflight
INTO @DATA(lwa_data).
SELECT concat( carrid , currcode ) AS concat,
carrid && currcode AS concat_sign,
concat_with_space( carrid , currcode , 1 ) AS with_space,
instr( carrid , 'BA' ) AS instr,
left( carrname , 4 ) AS left,
right( carrname , 4 ) AS right,
length( carrname ) AS length
FROM scarr
INTO TABLE @DATA(lt_data)
UP TO 5 ROWS.
DATA(lv_date) = CONV datum( '20181022' ).
SELECT fldate AS original_date,
dats_is_valid( fldate ) AS valid_date,
tims_is_valid( @sy-uzeit ) AS valid_time,
dats_days_between( fldate , @lv_date ) AS between,
dats_add_days( fldate , 10 ) AS add_days,
dats_add_months( fldate , 3 ) AS add_months
FROM sflight
INTO TABLE @DATA(lt_data)
UP TO 3 ROWS.
DATA(lv_stamp_now) = CONV timestamp( '20190603133559' ).
DATA(lv_stamp_past) = CONV timestamp( '20190602161408' ).
SELECT tstmp_is_valid( @lv_stamp_now ) AS valid_stamp,
tstmp_current_utctimestamp( ) AS current_stamp,
tstmp_seconds_between( tstmp1 = @lv_stamp_past,
tstmp2 = @lv_stamp_now,
on_error = @sql_tstmp_seconds_between=>set_to_null ) AS between,
tstmp_add_seconds( tstmp = @lv_stamp_now,
seconds = @( CONV timestamp( 999 ) ),
on_error = @sql_tstmp_add_seconds=>set_to_null ) AS add_second
FROM sflight
INTO TABLE @DATA(lt_data)
UP TO 1 ROWS.
SELECT abap_user_timezone( user = @( CONV uname( 'JIANGRE' ) ),
client = '130',
on_error = @sql_abap_user_timezone=>set_to_null ) AS user_zone,
abap_system_timezone( client = '130',
on_error = @sql_abap_system_timezone=>set_to_null ) AS sys_zone
FROM sflight
INTO TABLE @DATA(lt_data)
UP TO 1 ROWS.
DATA(lv_stamp) = CONV timestamp( '20190603133559' ).
SELECT tstmp_to_dats( tstmp = @lv_stamp,
tzone = @( CONV tznzone( 'CET' ) ) ) AS dats,
tstmp_to_tims( tstmp = @lv_stamp,
tzone = @( CONV tznzone( 'CET' ) ) ) AS tims,
tstmp_to_dst( tstmp = @lv_stamp,
tzone = @( CONV tznzone( 'CET' ) ) ) AS dst,
dats_tims_to_tstmp( date = @sy-datum,
time = @sy-uzeit,
tzone = @( CONV tznzone( 'CET' ) ) ) AS tstmp
FROM sflight
INTO TABLE @DATA(lt_data)
UP TO 1 ROWS.
WHERE Condition
WHERE与HAVING的区别:WHERE 子句的搜索条件在进行分组操作之前应用;而 HAVING 的搜索条件则在进行分组操作之后应用
常用的条件语句,整理如下:
[ NOT ] IN:除了 SELECT-OPTION,也支持多个自定义或者通过子查询获取的值
ANY/SOME/ALL:允许将子查询获取到的结果集作为限制条件使用
[ NOT ] BETWEEN … AND …:使用范围条件
[ NOT ] LIKE … [ ESCAPE ]:使用模糊查询
IS [ NOT ] NULL:判断是否有关联到相应的记录
IS [ NOT ] INITIAL:判断是否为空值
[ NOT ] EXISTS:根据指定条件到数据库表查询数据,判断查询结果是否存在
like_regexpr:匹配正则表达式
SELECT i~*
FROM scarr AS r
LEFT OUTER JOIN spfli AS i ON i~carrid = r~carrid
WHERE i~carrid IN ( 'AA' , 'CO' )
AND i~carrid IN ( SELECT DISTINCT carrid FROM sflight )
AND i~carrid = ANY ( SELECT DISTINCT carrid FROM sflight )
AND i~carrid NOT BETWEEN 'BA' AND 'CA'
AND ( i~carrid LIKE 'A%' OR i~carrid LIKE 'C%' )
AND r~carrid IS NOT NULL
AND i~carrid IS NOT INITIAL
AND EXISTS ( SELECT carrid FROM sflight WHERE carrid = i~carrid )
INTO TABLE @DATA(lt_data).
************
where like_regexpr( pcre = '^[Aa]\s*\w+', value = mara~matnr ) > 0
更多精彩尽在se26: CL_ABAP_MATCHER, CL_ABAP_REGEX;
JOIN Expression
在特定的应用场景中,需要使用字符长度不一致的两个字段进行关联时,可以使用相应的表达式处理,但要注意表达式的位置,一般需要放在等式左边,如下例
"例:(NAST-OBJKY类型为CHAR30,EKKO-EBELN类型为CHAR10)
SELECT k~ebeln,
t~kschl
FROM nast AS t
INNER JOIN ekko AS k ON left( t~objky, 10 ) = k~ebeln
INTO TABLE @DATA(lt_data).
Aggregate Expressions
聚合表达式用于对一组值执行计算并返回单一的值,可以使用在SELECT或HAVING子句中,不能用在WHERE子句
常见的聚合表达式如下,表达式内部可选用DISTINCT对数据去重后再进行处理:
AVG:返回结果集的平均值,返回类型默认为浮点型,可通过AS语句返回指定类型,如DEC,CURR,QUAN或FLTP
MAX:返回结果集的最大值
MIN:返回结果集的最小值
SUM:返回结果集的汇总值
COUNT:返回结果集的条目数,通常情况下使用COUNT( * ) / COUNT(*),需要使用DISTINCT时则要指定字段名
更多聚合函数,尽在F1:
… AVG, MEDIAN, MAX, MIN, SUM, PRODUCT, STDDEV, VAR, CORR, CORR_SPEARMAN,
STRING_AGG, COUNT, GROUPING( col ), ALLOW_PRECISION_LOSS( … )