ABAP关键字SUBMIT的简单例子和学习小记
网上有关SUBMIT实现程序调用的例子稍显复杂,而相关的参考和解释则不是很完善。本文给出一个SUBMIT的小示例程序(代码见文末),实现了最简单的程序间调用及返回值,以及SAP官方文档中相关内容的翻译、解释。
本文链接:http://www.cnblogs.com/hhelibeb/p/5802398.html
转载请注明
SUBMIT - 参考
语法
SUBMIT {rep|(name)}
[USING SELECTION-SCREEN dynnr]
[VIA SELECTION-SCREEN]
[USING SELECTION-SET variant]
[USING SELECTION-SETS OF PROGRAM prog]
[WITH SELECTION-TABLE rspar]
{ [WITH sel1 { {{EQ|NE|CP|NP|GE|LT|LE|GT} dobj [SIGN sign]}
| {[NOT] BETWEEN dobj1 AND dobj2 [SIGN sign]}
| {IN rtab} }]
[WITH sel2 { {{EQ|NE|CP|NP|GE|LT|LE|GT} dobj [SIGN sign]}
| {[NOT] BETWEEN dobj1 AND dobj2 [SIGN sign]}
| {IN rtab} }]
... }
[WITH FREE SELECTIONS texpr]
[LINE-SIZE width]
[LINE-COUNT page_lines]
{ [EXPORTING LIST TO MEMORY]
| [TO SAP-SPOOL SPOOL PARAMETERS pri_params
[ARCHIVE PARAMETERS arc_params]
WITHOUT SPOOL DYNPRO] }
[[USER user] VIA JOB job NUMBER n]
[AND RETURN].
效果
调用一个可执行程序。
附加项
-
{rep|(name)}
使用rep静态地指定一个程序,或者使用name动态地指定
-
USING SELECTION-SCREEN dynnr
指定要访问的选择屏幕dynnr,如不使用该条目,系统调用标准选择屏幕。
-
VIA SELECTION-SCREEN
显示被调用的选择屏幕。如不使用该条目,选择屏幕过程(selection screen processing)将会在后台发生。
-
USING SELECTION-SET variant
选择屏幕使用变式
-
USING SELECTION-SETS OF PROGRAM prog
指定使用的变式的程序
-
WITH SELECTION-TABLE rspar
选择屏幕使用内表rspar中的值,内表的行结构为RSPARAMS或者RSPARAMSL_255,如图
-
WITH sel1 ... WITH sel2 ...
传入单独的参数和条件值(selection criteria ) sel1, sel2....给选择屏幕:
- {EQ|NE|CP|NP|GE|LT|LE|GT} dobj [SIGN sign] - 传输一个单值和相关的操作符,以及selection table中SIGN列的设定
- [NOT] BETWEEN dobj1 AND dobj2 [SIGN sign] - 传输一个从dobj1到dobj2之间的区间和可选的操作符NOT,以及selection table中SIGN列的设定
- in rtab - 传输一个Range Table rtab
tips: Range Table
Range Table为系统标准内表,结构与Selection Table一致,由SIGN, OPTION, LOW, HIGH和条件值字段组成; 可以通过 TYPE RANGE OF 语句或 RANGES 关键字定义 Range Table。 Range Table 常用于Open SQL语句中的条件筛选,可以优化取数效率与程序性能。 |
例子:
REPORT report1. "program accessed DATA text TYPE c LENGTH 10. SELECTION-SCREEN BEGIN OF SCREEN 1100. SELECT-OPTIONS: selcrit1 FOR text, selcrit2 FOR text. SELECTION-SCREEN END OF SCREEN 1100. ...
REPORT report2. "calling program DATA: text TYPE c LENGTH 10, rspar_tab TYPE TABLE OF rsparams, rspar_line LIKE LINE OF rspar_tab, range_tab LIKE RANGE OF text, range_line LIKE LINE OF range_tab. ... rspar_line-selname = 'SELCRIT1'. rspar_line-kind = 'S'. rspar_line-sign = 'I'. rspar_line-option = 'EQ'. rspar_line-low = 'ABAP'. APPEND rspar_line TO rspar_tab. range_line-sign = 'E'. range_line-option = 'EQ'. range_line-low = 'H'. APPEND range_line TO range_tab. range_line-sign = 'E'. range_line-option = 'EQ'. range_line-low = 'K'. APPEND range_line TO range_tab. SUBMIT report1 USING SELECTION-SCREEN '1100' WITH SELECTION-TABLE rspar_tab WITH selcrit2 BETWEEN 'H' AND 'K' WITH selcrit2 IN range_tab AND RETURN.
结果:在report1被report2访问之后,被访问程序中的条件值selcrit1和selcrit2的selection table中包含了以下记录:
SIGN | OPTION | LOW | HIGH | |
selcrit1 | I | EQ | ABAP | |
selcrit2 | I | BT | H | K |
selcrit2 | E | EQ | H | |
selcrit2 | E | EQ | K |
-
WITH FREE SELECTIONS texpr
通过一个内表texpr向选择屏幕提供基于逻辑数据库的动态选择,内表texpr的类型是RSDS类型组中的RSDS_TEXPR
-
LINE-SIZE width
使用width设置程序访问的Basic List的行宽
tips: Basic List
Basic List: 参考List Screen的相关内容。 在START-OF-SELECTION事件处理块中,用WRITE语句向列表缓冲区(List Buffer)输出要显示的内容。 当该事件结束的时候,所有在列表缓冲区中的内容将被显示到一个基本列表屏幕(Basic List)上。 |
-
LINE-COUNT page_lines
使用设置程序访问的Basic List的页包含的行数
-
EXPORTING LIST TO MEMORY
将程序访问的Basic List以行类型为ABAPLIST的内表形式保存到ABAP Memory中
-
TO SAP-SPOOL
为程序访问的basic list创建一个spool request,并带有以下参数:
- SPOOL PARAMETERS pri_params - 打印参数,保存在类型为PRI_PARAMS的结构pri_params中
- ARCHIVE PARAMETERS arc_params - 归档参数,保存在类型为ARC_PARAMS的结构arc_params中
- WITHOUT SPOOL DYNPRO - 阻止打印对话框
-
[USER user] VIA JOB job NUMBER n
有待后续补充 效果:
此附加项将被访问的程序安排为后台任务运行,后台请求作业号为n。后台请求作业号n由函数组BTCH中的函数JOB_OPEN提供。整个程序不是直接运行的,而是根据后台请求指定的参数在后台过程中运行。你可以使用可选的附加项USER去指定一个类型为sy-uname的用户ID user,这个ID用于运行后台任务。附加项VIA JOB只能和AND RETURN一起使用。
当submit语句执行时,VIA JOB也独立地在内部模式中加载被访问的程序,在被访问的程序中,系统会执行在START-OF-SELECTION事件之前指定的所有步骤。这意味着事件LOAD-OF-PROGRAM和INITIALIZATION会被触发,selection screen processing会执行。如果指定了附加项VIA SELECTION-SCREEN使得选择屏幕不在后台处理,调用程序的用户可以编辑选项并且使用函数PLACE IN JOB安排被访问的程序在后台请求中运行。如果用户取消了selection screen processing,程序不会被安排后台作业中。在这两种情况下,被执行程序的执行都是完全在selection screen processing之后执行的,并因为AND RETURN附加项的存在,系统会返回调用程序。
当程序被安排为后台任务时,用户或附加项指定的、用来填充选择屏幕的选择条件存储在一个内部变式中。当程序在后台请求中执行时,选择条件被完全地处理,但是选择屏幕是在后台运行的。系统触发所有的事件,包括selection screen processing的。内部存储的变式在INITIALIZATION和AT SELECTION SCREEN OUTPUT事件之间传递给选择屏幕。
如果被访问的程序创建了一个基本列表屏幕,你应该通过使用指定TO SAP-SPOOL的方式,来创建一个带有显式打印参数的spool request。否则VIA JOB附加项会隐式地创建一个spool request,这个spool request继承自它的来自于标准值的打印参数,有的标准值是用户默认的,不一定符合相应的需要。
系统字段
sy-subrc | 含义 |
0 | 后台任务计划成功 |
4 | 用户在选择屏幕中断了计划 |
8 | 计划过程中的错误, 发生在JOB_SUBMIT的内部调用中. |
12 | 内部号分配过程中的错误 |
注:
你可以通过选择菜单 系统(System)——服务(Services)——作业(Jobs)创建和监视后台作业。这里显示的语言元素在内部被使用。除了JOB_OPEN以外,ABAP程序中也可以使用函数JOB_CLOSE和JOB_SUBMIT。函数JOB_CLOSE可以关闭后台请求的创建。JOB_SUBMIT通过后台请求安排一个ABAP程序成为后台任务,像SUBMIT语句那样。而JOB_SUBMIT为后台处理(background processing)提供更多的控制选项,但是必须从已经存在的变式来获得选择屏幕的值。SUBMIT语句可以创建一个内部变式,并且在内部访问JOB_SUBMIT。
例子:
使用后台请求name中的作业号number来把一个程序安排为后台任务。在设定后,后台任务由函数JOB_CLOSE完成,并且立即发布,同时提供给用户的相关权限。
DATA: number TYPE tbtcjob-jobcount, name TYPE tbtcjob-jobname VALUE 'JOB_TEST', print_parameters TYPE pri_params. ... CALL FUNCTION 'JOB_OPEN' EXPORTING jobname = name IMPORTING jobcount = number EXCEPTIONS cant_create_job = 1 invalid_job_data = 2 jobname_missing = 3 OTHERS = 4. IF sy-subrc = 0. SUBMIT submitable TO SAP-SPOOL SPOOL PARAMETERS print_parameters WITHOUT SPOOL DYNPRO VIA JOB name NUMBER number AND RETURN. IF sy-subrc = 0. CALL FUNCTION 'JOB_CLOSE' EXPORTING jobcount = number jobname = name strtimmed = 'X' EXCEPTIONS cant_start_immediate = 1 invalid_startdate = 2 jobname_missing = 3 job_close_failed = 4 job_nosteps = 5 job_notex = 6 lock_failed = 7 OTHERS = 8. IF sy-subrc <> 0. ... ENDIF. ENDIF. ENDIF.
-
AND RETURN
AND RETURN通过运行时环境决定了在程序被调用后的访问对象:
- 没有AND RETURN关键字的时候,伴随着SAP LUW的退出,被访问程序的内部会话在访问队列的相同位置替代了访问程序的内部会话。一旦程序访问结束,系统返回到调用程序开始的位置。SUBMIT上系统字段SY-CALLD复制调用程序的值。
- AND RETURN关键字在一个新的内部会话中运行程序。调用程序和当前的SAP LUW会保持存在。被调用程序运行它自己的SAP LUW。一旦程序访问结束,程序将继续执行SUBMIT语句之后的内容。
tips: SAP LUW, SY-CALLD
SAP LUW:SAP logical unit of work(LUW)是一个逻辑单位,我们把需要完成的工作分成一个个独立的单元(LUW),每个单元包含若干操作,这些操作要么完全执行,要么完全不执行 (all-or-nothing principle)。相应地,数据库层面存在更小的单元Database LUW。 SY-CALLD: 在一个调用序列中的第一个程序里为空字符串,否则为值“X”。在调用using CALL TRANSACTION,CALL DIALOG或 者SUBMIT ... AND RETURN后变为“X”。如果程序以LEAVE TO TRANSACTION或者从一个屏幕事务开始的话,则为空。使用SUBMIT(没有AND RETURN)时设定为调用它的程序的值。 |
注:
- 如果在一个submit里依然有注册在当前的SAP LUW中的程序,且没有 AND RETURN,SAP LUW的退出没有伴随着调用或者回滚程序。已注册的更新函数(update function modules)会保留在数据库中,但是无法再运行。为了防止这种情形,你可以在程序调用前显式地执行语句COMMIT WORK或者ROLLBACK WORK。
- 带有AND RETURN的SUBMIT语句开启了一个新的SAP LUW,但是注意并不会自动开启一个新的database LUW。这意味着在这个SAP LUW中使用语句 CALL FUNCTION IN UPDATE TASK或者CALL FUNCTION IN BACKGROUND TASK in the tables VB... or ARFCSSTATE and ARFCSDATA会回滚全部登记项。在某些情况下,被调用程序的ROLLBACK WORK语句也会影响到暂停的SAP LUW。为了防止这点,必须在程序被调用前显式地运行database commit。这个问题不会在本地模式更新中发生。
tips: 本地模式
更新数据库的几种模式:异步模式、同步模式、本地模式。 |
异常
- ·原因:未找到指定程序
运行时错误:LOAD_PROGRAM_NOT_FOUND
- 原因:尝试使用SIGN传输一个无效的选择值
运行时错误:SUBMIT_WRONG_SIGN
- 原因:指定程序不是一个report
运行时错误:SUBMIT_WRONG_TYPE
tips: 程序类型
1 REPORT(报表) M PROGRAM(屏幕程序) F FUNCTION-POOL(函数组) K CLASS-POOL(类组) J CLASS-POOL(接口组) T TYPE-POOL(类型池) |
- 原因:尝试向报表参数传输一个以上的值
运行时错误:SUBMIT_IMPORT_ONLY_PARAMETER
- 原因:尝试使用WITH sel IN itab传输的表的结构与selection不符合
运行时错误:SUBMIT_IN_ITAB_ILL_STRUCTURE
- 原因:尝试传输一个不能被转换为选择屏幕目标字段的参数
运行时错误: SUBMIT_PARAM_NOT_CONVERTIBLE
- 原因:被调用程序存在语法错误
运行时错误: SYNTAX_ERROR
程序示例
示例包含3个程序,调用程序CALLING,被调用程序 ACCESSED1和ACCESSED2。
其中,ACCESSED1和ACCESSED2均为独立可运行的REPORT程序,带有标准选择屏幕,可以将选择屏幕输入的数值计算后输出到屏幕。
在CALLING程序中,我们可以在选择屏幕输入一个值,运行后,分别调用ACCESSED1和ACCESSED2进行数值处理,并显示在CALLING的结果屏幕中,这是调用过程的简单示意图:
CALLING程序代码如下:
REPORT ztestcalling. CONSTANTS: g_memory1(30) VALUE 'JACKYTESTA'."定义MEMORY ID CONSTANTS: g_memory2(30) VALUE 'JACKYTESTB'. DATA: val_return_from_accessed1 TYPE i, val_return_from_accessed2 TYPE i. DATA: selectable LIKE TABLE OF rsparams. "选择参数内表 DATA: selectline LIKE LINE OF selectable. SELECTION-SCREEN BEGIN OF BLOCK blk. PARAMETERS: p_value TYPE i. SELECTION-SCREEN END OF BLOCK blk. INITIALIZATION. START-OF-SELECTION. selectline-selname = 'P_VALUE'. "选择屏幕字段名 selectline-kind = 'P'. "选择类型为单选,如果是多选则为S selectline-low = p_value. "选择字段的值 APPEND selectline TO selectable. SUBMIT ztestACCESSED1 WITH SELECTION-TABLE selectable AND RETURN. IMPORT val TO val_return_from_accessed1 FROM MEMORY ID g_memory1. "取出ABAP内存中的数据 FREE MEMORY ID g_memory1. "释放MEMORY ID SUBMIT ztestACCESSED2 WITH SELECTION-TABLE selectable AND RETURN. IMPORT val TO val_return_from_accessed2 FROM MEMORY ID g_memory2. FREE MEMORY ID g_memory2. SKIP. WRITE: '程序ACCESSED1的运行结果是', p_value, '+ 1 =', val_return_from_accessed1 . WRITE: /'程序ACCESSED2的运行结果是', p_value, '* 3 =', val_return_from_accessed2 .
接下来是被调用的ACCESSED1和ACCESSED2,程序内容基本一致,不同之处在于使用了不同的memory id传输数据。
REPORT ztestACCESSED1. DATA val TYPE i. CONSTANTS: g_memory1(30) VALUE 'JACKYTESTA'. SELECTION-SCREEN BEGIN OF BLOCK blk1. PARAMETERS: p_value TYPE i. SELECTION-SCREEN END OF BLOCK blk1. INITIALIZATION. START-OF-SELECTION. val = p_value + 1. IF sy-calld = 'X'. EXPORT val FROM val TO MEMORY ID g_memory1. ELSE. WRITE val. ENDIF.
REPORT ztestACCESSED2. DATA val TYPE i. CONSTANTS: g_memory2(30) VALUE 'JACKYTESTB'. SELECTION-SCREEN BEGIN OF BLOCK blk1. PARAMETERS: p_value TYPE i. SELECTION-SCREEN END OF BLOCK blk1. INITIALIZATION. START-OF-SELECTION. val = p_value * 3. IF sy-calld <> 'X'. WRITE val. ELSE. EXPORT val FROM val TO MEMORY ID g_memory2. ENDIF.
运行CALLING程序,输入数字2:
点击运行,直接显示两个程序的计算结果:
说明和注意
在实际应用当中,我们很可能需要判断一个程序是独立运行的,还是处于被调用状态,以决定接下来的处理逻辑(展示结果/传输结果),这时需要使用系统字段SY-CALLD:
字段名 | 类型 | 长度 | 应用目标 | 说明 | ||
SY-CALLD | CHAR | 1 | ABAP程序 | ABAP程序调用模式 |
SY-CALLD通过一个标识符显示程序是否被调用。以上面的程序为例,如果ACCESSED1和ACCESSED2是独立运行的,则SY-CALLD应为空;而在被程序CALLING调用时,SY-CALLD的值为“X”。
需要注意的一点是,如果在SE38中运行ACCESSED1和ACCESSED2,SY-CALLD的值为'X'。这使得我们无法看到本应由WRITE语句输出的计算结果。如果是复杂一些的程序,这种现象可能会给调试带来麻烦。查询系统字段的解释:
英文:Contains a blank character in the first program in a call sequence, otherwise contains the value "X". Is set to "X" after calls using CALL TRANSACTION, CALL DIALOG, or SUBMIT ... AND RETURN. Empty if the program was started using LEAVE TO TRANSACTION or a transaction from the screen. A call using SUBMIT (without AND RETURN) assumes the value of the calling program.
中文:在一个调用序列中的第一个程序里为空字符串,否则为值“X”。在调用using CALL TRANSACTION,CALL DIALOG或者SUBMIT ... AND RETURN后变为“X”。如果程序以LEAVE TO TRANSACTION或者从一个屏幕事务开始的话,则为空。使用SUBMIT(没有AND RETURN)时设定为调用它的程序的值。
由此,我们有如下解决该问题的办法:
- 分配事务代码,在SAP主屏幕使用事务代码运行程序,则SY-CALLD为空。
- 在1的基础上,也可以单独创建一个可执行程序,在这个新程序中,使用LEAVE TO TRANSACTION调用ACCESSED1或者ACCESSED2。
2017.07.26更新:通常,后台运行的程序的系统变量sy-batch的值应该为'X',但在特定情况下也可能不是这样,比如调用F.13作为后台程序运行的时候。这时可以尝试观察sy-ucomm的值(jobs),来确定程序是否处于后台状态。
SALV - 在submit后获取数据
对于获取某些既有ALV报表数据的需求,可以使用submit来满足,并且不需要修改既有报表程序的代码。
如果你不想在调用后输出报表,但是又想获取数据,可以在调用前使用以下代码:
cl_salv_bs_runtime_info=>set( display = SPACE metadata = SPACE data = ‘X’ ).
调用后,通过以下代码获取数据,
DATA lo_data TYPE REF TO data. TRY. " get data from the SALV model cl_salv_bs_runtime_info=>get_data_ref( IMPORTING r_data = lo_data ). CATCH cx_salv_bs_sc_runtime_info. Message 'Unable to get data from SALV' type 'I'. ENDTRY.
例子
这里使用一个对SALV_DEMO_TABLE_SIMPLE的调用来作为例子,
DATA: lt_outtab TYPE STANDARD TABLE OF alv_t_t2. FIELD-SYMBOLS: <lt_outtab> like lt_outtab. DATA lo_data TYPE REF TO data. " Let know the model cl_salv_bs_runtime_info=>set( display = abap_false metadata = abap_false data = abap_true ). SUBMIT salv_demo_table_simple AND RETURN. TRY. " get data from SALV model cl_salv_bs_runtime_info=>get_data_ref( IMPORTING r_data = lo_data ). ASSIGN lo_data->* to <lt_outtab>. BREAK-POINT. CATCH cx_salv_bs_sc_runtime_info. ENDTRY.
请注意,这是一种比直接使用Export/Import更好的办法,因为不需要管理Memory ID,也不再需要对被调用的报表进行侵入式的修改。
相关阅读:ABAP程序间传递数据的几种方法
ABAP程序互调用:SUBMIT、CALL TRANSACTION、LEAVE TO TRANSACTION
原创内容,转载请注明本文链接。