SAP(五)模块化程序

  • Post author:
  • Post category:其他



模块化程序

  1. 子程序

    子程序是以FROM开始,以END FROM结束的语句。
PERFROM write_data.
 FORM write_data.
     WRITE  '11111'.
     ULINE.
     ENDFORM.
  1. 子程序参数

    [子程序参数Using和Changing的区别(https://www.cnblogs.com/foxting/archive/2012/08/01/2619091.html)

    USING 之后跟随着不会发生变化的子程序参数,CHANGING后面的参数按引用传递,值会随着子程序内的变化而变化。

2.1 Call by Value

实参与虚参有不同的物理地址(用USING与Value在一起搭配的情况)

虚参占有自己单独的内存,调用子程序时,实参值复制到虚参中,改变虚参值不影响实参值。

2.2 Call by Reference

有相同的物理地址并相互传递地址(用CHANGING与Value在一起搭配的情况)

虚参没有自己单独的内存,调用子程序时,虚参占用实参的地址(相同名字的变量内存中工作)

若FROM不使用VALUE语句,则USING和CHANGING功能一样,USING传递参数,CHANGING传递数据后变更的值。一般情况USING要与VALUE语句一起使用。

2.3 Call by Value and Result

传入传出执行成功后返回变更后的值,不同的物理地址

USING与VALUE搭配时无法修改子程序中的虚参值,而CHANGING与Value当正常结束子程序时会修改实参值。


FIELD-SYMBOLS

TYPES : BEGIN OF t_str,
          col1 TYPE c,
          col2 TYPE i,
        END OF t_str. "定义结构体

TYPES: tt_str TYPE TABLE OF t_str."定义内表形式

DATA : gs_str  TYPE t_str,"根据结构体分别定义变量和内表,内表具有两列
       "pt_itab TYPE STANDARD TABLE OF t_str.
       gt_itab TYPE STANDARD TABLE OF t_str.

gs_str-col1 = 'A'.
gs_str-col2 = 1.
APPEND gs_str TO gt_itab.

gs_str-col1 = 'B'.
gs_str-col2 = 2.
APPEND gs_str TO gt_itab.

PERFORM test_itab USING gt_itab. "gt_itab是实参,内表类型
*调用程序要传输的数据gt_itab,把gt_itab的值传递到pt_itab 
FORM test_itab USING pt_itab TYPE  tt_str.
*FORM test_itab USING pt_itab TYPE  any table.形参指定为任意表类型, 下面的read要用动态条件,即传值进去,不然动态表找不到列名

  READ TABLE pt_itab WITH  KEY col1 = 'A'  INTO gs_str.
  *查询条件col1 = 'A',读取第一次的值赋值到gs_str.从表中读取符合条件的数据保存到变量
  IF sy-subrc EQ 0.
    WRITE : / gs_str-col1,gs_str-col2.
  ENDIF.

ENDFORM.

当不知道程序的运行逻辑时,可以去debug

在这里插入图片描述
在这里插入图片描述
表双击可以查看具体信息。

在这里插入图片描述

  1. TYPES与DATA的区别:

    TYPES 只是定义了一个 结构 ,是不占用内存的,不能直接用来存放数据。

    DATA 定义了一个 变量 ,是需要占用内存的,可以用来存放数据。

    定义一个变量的时候可以引用一个结构(用type),但是定义结构的时候就不能引用一个变量了(一般变量引用结构).

    TYPES是用来创建用户定义的基本数据类型和结构化数据类型和定义内表式的数据类型,通过TYPES定义的类型不能直接使用,需要DATA进行定义其对应的变量后才可使用,定义结构化数据对象和定义内表。

TYPES: address TYPE C.
DATA: address TYPE address.

3.1 like standard table of和type standard table of有什么区别

1、TYPE后面跟随的只能是某种类(型),

2、而LIKE后面可以跟实例对象,参照结构体对象生成内表时只能用LIKE,不能用TYPE,因为结构体对象不是类型,只是一种实例对象,参照结构类型生成内表时可以用LIKE也可以用TYPE.

3、其中通过LIKE定义的内表直接拥有参照结构类型的元素结构,

4、而通过TYPE定义的内表只能间接拥有被参照结构类型的元素结构,结构类型不能作为内表的工作区,只有结构体对象才可以.

READ tabe 是用来遍历内表,取第一条符合条件的记录。

READ TABLE [INTO ] WITH KEY [BINARY SEARCH].

WITH KEY 中的检索条件比较符不能使用‘<>’(不等于)。

如果只想取得内部表中不等于某条件的一条记录,那么请使用下面变通方法。

 LOOP AT itab WHERE KEY <> ‘XX’.

          此处取得第一条记录。

          EXIT.

       ENDLOOP.

如果在运行时 值为空,则 统忽略该关键字段。另外可对关键字段指定偏移量和长度。

用 INTO 选项可以指定目标区域 。如果表格有表头行,则可以忽略 INTO 选项。这样,表格工作区域就成了目标区域。

系统读取 中匹配 中所定义的关键字的第一个条目。

如果使用二分法搜索法的话,需要先对内表进行相关条件的排序。

SORT pt_itab DESCENDING BY 排序的列.
 READ TABLE pt_itab WITH  KEY= 'A' BINARY SEARCH INTO gs_str.
 *BINARY SEARCH二分法

如果找到有适当关键字的条目,则将系统字段 SY-SUBRC设置为0,并且SY-TABIX包含该行的索引。否则,将 SY-SUBRC设置为非0值 。

3.2

TABLES,USING,CHANGING


函数的使用顺序—TABLES,USING,CHANGING,三者顺序不可颠倒

SAP使用PERFORM的时候:

在这里插入图片描述
注意:上表中的引用传递即ABAP中的字段符号(别名)传递,而不是说传递的实参内容为真正的传址,至于传递的是地址还是直接为变量内容,则同样要看形参类型是否定义为了 REF TO 类型

FORM subr 
[TABLES t1 [{TYPE itab_type}
|{LIKE itab}|{STRUCTURE struc}]
t2 []] 

[USING { VALUE(p1)|p1 } [ { TYPE generic_type }
| { LIKE <generic_fs>|generic_para }
| { TYPE {[LINE OF] complete_type}|{REF TO type} }
| { LIKE {[LINE OF] dobj} | {REF TO dobj} }
| STRUCTURE struc]
{ VALUE(p2)|p2 } []] 

[CHANGING{ VALUE(p1)|p1 } [ { TYPE generic_type }
| { LIKE <generic_fs>|generic_para } 
| { TYPE {[LINE OF] complete_type} | {REF TO type} }
| { LIKE {[LINE OF] dobj} | {REF TO dobj} }
| STRUCTURE struc]
{ VALUE(p2)|p2 } []] 

[RAISING {exc1|RESUMABLE(exc1)} {exc2|RESUMABLE(exc2)} ...].
  1. 使用内表指定

1、使用Generic type

FROM subr CHANGING pt_itab TYPE TABLE.
FROM subr CHANGING pt_itab TYPE ANY TABLE.
FROM subr CHANGING pt_itab TYPE INDEX TABLE.
FROM subr CHANGING pt_itab TYPE STANDARD TABLE.
FROM subr CHANGING pt_itab TYPE SORTED TABLE.
FROM subr CHANGING pt_itab TYPE HASHED TABLE.

2、使用与实参相同的内表类型

FROM subr CHANGING pv_val TYPE i_tab.

3、使用与实参具有相同类型的内表

FROM subr CHANGING pv_val LIKE gt_itab.
  1. 调用子程序。

    调用子程序的方法有Inetrnal/External,外部调用的子程序名后面要明确指定盖子程序所属程序名

    通过perform可以调用ABAP程序内部子程序,也可以调用其他程序的子程序

    5.1 调用语法

PERFORM sub.
PERFORM subr(prog) [IF FOUND]. 括号内是外部程序名

5.2 调用内部子程序

调用内部子程序
DATA : gv_val1(20) TYPE c VALUE  'Zhou',
       gv_val2(20) TYPE c VALUE 'Huiting',
       gv_val3(40) TYPE c.
PERFORM concate_string USING gv_val1 gv_val2
      CHANGING gv_val3.

FORM concate_string USING VALUE(p_val1) VALUE(p_val2)
  CHANGING VALUE(p_val3).
  CONCATENATE  p_val1 p_val2 INTO p_val3 SEPARATED BY space.
  PERFORM write_data USING p_val3.
ENDFORM.

FORM write_data USING VALUE(p_val).
  WRITE : / p_val.
ENDFORM.

5.2 调用外部子程序

*调用程序外部子程序
     DATA : gv_val6(20) TYPE c VALUE  'cas',
       gv_val4(20) TYPE c VALUE 'e',
       gv_val5(40) TYPE c .
 PERFORM concate_string(zhello) IF FOUND
        USING gv_val6 gv_val4
       CHANGING gv_val5.

5.3 动态指定子程序名字

动态指定子程序名字
 DATA : gv_val9(20) TYPE c VALUE  '知否知否',
       gv_val10(20) TYPE c VALUE '应是绿肥红瘦',
       gv_val11(40) TYPE c ,
       gv_val7(8) TYPE c VALUE 'zhello',
       gv_val8(40) TYPE c VALUE 'CONCATE_STRING'."要用大写,不然系统识别不到
    TRANSLATE GV_VAL7 TO UPPER CASE.               "转换成大写,不然系统识别不到
 PERFORM (gv_val8) IN PROGRAM (gv_val7) IF FOUND
        USING gv_val9 gv_val10
       CHANGING gv_val11.

5.4 利用list调用子程序

DO 2 TIMES.
  PERFORM SY-INDEX OF subr1 subr2.
ENDDO.

FORM subr1.
  WRITE / '1 subroutine is called'.
ENDFORM.
FORM subr2.
  WRITE / '2 subroutine is called'.
ENDFORM.

5.5 循环

do ~ while

可以指定循环次数的语句,不指定次数,进入死循环

循环次数保存在系统变量sy-index

while ~ endwhile

当while语句的表达式结果为真,进入循环

循环次数保存在系统变量sy-index

loop ~ endloop

按顺序依次循环内表,将读取内表行数据保存到工作区或者表头的循环语句.

循环次数保存在系统变量sy-index, sy-tabix表示内表的当前行数

  1. 结束子程序

    endform, 正常结束

    exit, 直接跳出子程序

    check, 结果为假跳出子程序

parameters: p_val type char10.
perform end_subr using p_val.
form end_subr using value(p_val).
  case p_val.
    when 'EXIT'.  "屏幕输入后系统会转换成大写
      write 'subroutine exit'.
      exit.
    when 'CHECK'.
      write 'value check'.
    when others.
  endcase.
  write 'subroutine is normally ended'.
endform.                    "end_subr

6.1 判断语句

if condition.
~~~
elseif codition.
~~~
else.
~~~
endif.
case variable
when value1.
~~~
when value2.
~~~
when OTHERS.
~~~
endcase.

6.2 临时子程序

PERFORM ON COMMIT

using perform on cmmit, 遇到commit work时调用子程序

*debug去看
DATA : gs_scarr LIKE scarr,
       gv_flg   TYPE c.
SELECT SINGLE * FROM scarr INTO gs_scarr WHERE carrid ='AA'.  "gs_scarr存储1条数据

PERFORM delete_data USING gs_scarr.  "子程序正常执行
PERFORM insert_data ON COMMIT. "子程序定义时带有选项on commit,遇到commit work才执行

IF gv_flg = 'X'.
  COMMIT WORK.  "第二个子程序再这里开始执行
ENDIF.

FORM delete_data USING VALUE(ps_scarr) TYPE scarr.
  DELETE scarr FROM ps_scarr. "从表scarr中删除符合条件的条目
  IF sy-subrc = 0.
    gv_flg = 'X'.
  ENDIF.
ENDFORM.

FORM insert_data.
  INSERT scarr
  FROM gs_scarr.
ENDFORM.

6.3 局部macro

DATA:
  gv_val1 TYPE c VALUE 'A',
  gv_val2 TYPE c VALUE 'B',
  gv_val3 TYPE char3.

DEFINE conn.
  CONCATENATE &1 &2 INTO &3 SEPARATED BY space.
  dis &3.  "这里在调用一个define,作为实参传递过去
end-of-definition.

DEFINE dis.
  WRITE / &1. "打印传进来的内容
end-of-definition.

7.创建函数组

8.创建函数、测试函数、调用函数

DATA gv_result TYPE i.

CALL FUNCTION 'ZFM_01'
  EXPORTING
    1_num1 = 10
    1_num2  = 2
importing
  e_result  =  gv_result
exceptions
dv_zero = 1
others  = 2.

IF sy-subrc = 1.
  WRITE 'You can not divide by 0'.
  EXIT.
* Implement suitable error handling here
ENDIF.
WRITE : gv_result.

9.

RFC

了解即可



版权声明:本文为maomibook原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。