SAPABAP语⾔编程⼿册
第⼀章程序调试
编译任何程序最基本的技能就是对程序的调试(debugging). 所以让我们先熟悉⼀下SAP ABAP程序的调试⼿段。
如何调试ABAP程序?
在这本书中,我假设你使⽤的是ABAP编辑器(事务代码 SE38)开发ABAP程序。但是,如果你使⽤的是Object Navigator (事务代码 SE80)做开发⼯作,过程也是相同的。
在ABAP编辑器屏幕,采取以下步骤设置你的调试断点:
1. 选择你要开始调试的代码⾏。
2. 按“Session断点“钮。
如果要删除断点,只要双电击程序⾏上的Session断点图标(icone)即可删除断点。
提⽰:
如果你的SAP版本较⽼,点击断点图标后,会有⼀个画⾯弹出,让你选择是“Session断
点“还是”External断点“。
如果你要管理程序⾥设置的所有断点,你可以去菜单:实⽤程序(Utilities)> 断点。
如何调试Web应⽤程序?
如果你需要调试⼀个Web应⽤程序,设置断点的步骤和你设置ABAP程序断点完全相同,只是你设置的不是Session断点,⽽是外部断点(External Breakpoint)。
假设你在ABAP编辑器⾥编辑Web应⽤程序,请按照下⾯的步骤设置断点:
1.在Web应⽤程序⾥,选择你想要调试的代码⾏。
2.点击“External断点”按钮。
3.如果要删除断点,只要双电击程序⾏上的External断点图标(icone)即可删除断点
提⽰:
在较⽼版本上,点击断点图标后,会有⼀个画⾯弹出,让你选择是“Session断
点“还是”External断点“。
你也可以去菜单:“实⽤程序(Utilities)> External 断点“,去管理所有External断
点。
如何在程序⾥⼿动设置断点?
你可以在你的程序⾥设置断点语句,让程序在运⾏时只会为预先设定的⽤户停在断点。这样,其他⽤户可以⾃⾃如地运⾏程序,⽽你可以⾃由地调试程序。
语法
Break <User Logon ID>.
如果你代码中的登录ID和⽤户的登录ID相匹配的话,该程序运⾏到断点时会停⽌。
如何调试⼀个SAP事务(Transaction)?
你可以在事务命令代码框⾥使⽤“/H”命令,让后运⾏SAP事务。事务会停在最开始的程序⾏。
如何调试弹出屏幕?
前⾯提到,你可以在事务代码框⾥使⽤“/H”来调试事务。不过,如果你想调试在程序运⾏中弹出的屏幕,你就不能使⽤命令“/H”了。
这⾥给你个技巧提⽰,如何在屏幕弹出时进⾏调试:
在你的计算机上,⽤下⾯的代码创建⼀个⽂本⽂件,然后将其保存起来。
在SAPGUI窗⼝弹出时,把⽂本⽂件从Windows资源管理器的窗⼝⾥拖拉到SAPGUI弹出窗⼝。这时,SAPGUI就进⼊调试模式了。(在屏幕下,你可以看到”调试被激活“的信息。)代码范例
[FUNCTION]
Command=/H
Title=Debugger
Type=SystemCommand
如何调试在背景⼯作的程序?
如果你有权限可以更改程序,你可以使⽤这个⼩技巧调试在背景⼯作的程序。
在程序中你要调试的地⽅,加⼀个⽆限循环的逻辑。在这个⽆限循环的逻辑⾥,添加⼀个检查条件以便退出循环。例如,检查⼀个变量的值是否被更改。
·        开始在背景⾥运⾏程序。
·        运⾏事务SM50,等到你的程序显⽰在列表中。
·        到菜单:处理》程序》调试。(菜单路径可能在不同的版本中略有不同)
·        现在你的程序正在⽆限循环逻辑中。你可以改变变量的值,以便退出循环。
第⼆章程序基础
2.1数据处理
如何从⼀个⽂本字符串中删除尾随或前置的'0'或空格?
代码范例
SHIFT c RIGHT DELETING TRAILING c1.
SHIFT c LEFT DELETING LEADING c1.
在上⾯代码中的“C1”变量可以被定义为“空格”或“0”。
如何转移负号?
在SAP的世界⾥,负号标志是在数字的右侧,如“123.45-”。然⽽,在某些情况下,⽤户通常会要求把负号转移到左侧。例如,如果你的报表列表要下载到个⼈电脑上的Excel⽂件,⽤户将要求你重新安排负号。下⾯是代码范例
Data: p_amt(18).P_amt = '        12345.67-'.shift p_amt right deleting trailing '-
'.shift p_amt left deleting atenate '-'  p_amt into p_amt.
如何替换字符串?
你可以使⽤“TRANSLATE”语句来代替字符串中的字符。下⾯的代码范例可以把字符串⾥的‘X' 替换成”Y“。
代码范例
translate <string> using 'XY'.
如何分割⼀个被tab分隔(tab-delimited)的字符串?
你可以⽅便地使⽤“SPLIT”命令,分裂⼀个被分隔符分隔的字符串。在⼤多数情况下,分隔符是⼀个或多个字符,如“|”,"||",或','等,但是,” tab-delimited “分隔符是不同的。它必须定义为值是“09”的'×'类型。
下⾯的代码范例显⽰了如何分割tab分隔(tab-delimited)的字符串。请注意” tab-delimited “分隔符变量是如何定义的。
代码范例
Data: tab_del type x value '09'.
SPLIT <string> at tab_del into <field1> <field2> ….
如何删除字符串中的分隔符?
你可以先把分隔符除掉,然后再把所有分割后的⼦字符串串联在⼀起。
代码范例
DATA: tab_del TYPE C VALUE '|'.DATA: field1, field2, ……,
fieldn, final_str TYPE string.
SPLIT <string> AT tab_del  INTO: field1 field2 … fieldn.
CONCATENATE  field1 field2 … fieldn INTO final_str.
2.2条件运算符和循环
如何调⽤在另⼀个程序中的⼦程序?
语法
PERFORM <subroutine>(<program name>) using …
如何在程序之间传输数据?
为了在不同的程序之间传输数据,你可以先将数据保存到global ABAP内存,然后在另⼀个程序中读取它。
注意:数据传输完成后,⼀定要清⼲净global ABAP内存。
代码范例
Program 1
EXPORT obj1 ... objn TO MEMORY ID ‘m_id’.
Program 2
IMPORT obj1 ... objn FROM MEMORY. ID ‘m_id’.
… …
FREE MEMORY ID ‘m_id’.
如何使⽤“MOVE-CORRESPONDING”在两个结构之间复制数据?
如果你有两个结构,你想把同⼀字段类型(field type)的值从⼀个结构拷贝到另⼀个结构,你只要使⽤语句“MOVE-CORRESPONDING”来实现这⼀⽬标。只要⼀⾏代码即可。
然⽽,尽管这个命令⾮常⽅便,但对于CPU来说是⾮常昂贵的,因为“MOVE-CORRESPONDING”语句会逐⼀检查每⼀个字段的类型。因此,如果程序的运⾏速度要求很⾼,你可能需要⼀个字段⼀个字
段地拷贝。另外请注意,因为 “MOVE-CORRESPONDING”语句会逐⼀检查每⼀个字段的类型,如果你有两个相同类型的字段,你将会得到重复的数据。所以请先弄清楚两个结构的内容,然后再应⽤此命令。
语法。
MOVE-CORRESPONDING struc1 TO struc2.
如何把程序分配到不同的包(package)?
在事务SE38或者SE80窗⼝⾥,⽤右键单击Repository Browser窗⼝⾥的程序名。然后选择“更多功能“ à “更改包(Change package assignment)。
如何在循环(Loop),⼦程序(Subroutine)或报表程序(Report)⾥使⽤“EXIT”?
1。“EXIT”在循环(LOOP)结构⾥。
EXIT命令可以⽤来跳出循环结构,并终⽌循环的过程。
注意,在这⾥所说的“循环”结构不仅是指循环结构本⾝(Loop),⽽且还包括诸如DO, WHILE, SELECT等结构,
2。“EXIT”在⼀个⼦程序中(Subroutine)。
如果“EXIT”命令⽤在⼀个⼦程序或其它模块⾥,它是⽤来离开⼦程序或模块的。
“⼦程序”在这⾥指的是”FORM“结构,⽽“模块”是指如MODULE, FUNCTION, TOP-OF-PAGE, and END-OF-PAGE等结构。
请注意,
如果EXIT是在⼦程序或其他模块内的循环结构⾥,它只能让你跳出循环,但不能跳出⼦程序或模块。
3。“EXIT”在报表程序中(Report)。
如果EXIT既不在⼀个⼦程序或模块⾥,也不在循环结构⾥,那么它就会终⽌报表程序或者启动最后的清单显⽰。
如果EXIT既不在⼀个⼦程序或模块⾥,也不在循环结构⾥,那么它就会终⽌报表程序或者启动最后的清单显⽰。
如何使⽤“CHECK”语句,⽽不是”IF“语句?
1。“CHECK”语句⽤在循环(LOOP)中。
如果<logic expression>检查结果为负,当前循环进程终⽌,然后开始下⼀个循环。
session如何设置和读取2。“CHECK”在⼀个⼦程序(Subroutine)或报表程序(Report)⾥
如果<logic expression>检查结果为负,程序停⽌运⾏并退出当前的⼦程序或报表程序。
语法
CHECK <logic expression>.
和需要若⼲⾏的“IF”结构⽐较,CHECK”语句⼲净简洁。往往若⼲⾏的“IF”代码可以被只有⼀⾏的“CHECK“语句取代。
如何在循环结构中使⽤“AT…ENDAT”结构?
语法
Loop at itab.
At FIRST.
… … ... ...
ENDAT.
At LAST.
… … ... ...
ENDAT
ENDLOOP
2.3⽂件输⼊/输出
如何打开⼀个⽂件?
你可以使⽤下⾯的语句来打开⽂件。但请注意,如果你不使⽤任何附加值,打开的
⽂件只能进⾏读取⽽不能更改。⽽且是⼆进制模式。
如果你没有指定⽬录,系统将使⽤配置参数DIR_HOME定义的⽬录作为默认⽬录。
因此,我建议你在⽂件名变量⾥使⽤完整的⽂件路径,以避免混乱。
语法
OPEN DATASET <file_name>.
SY-SUBRC = 0. “⽂件打开.
SY-SUBRC = 8. “⽂件⽆法打开。
如何从⽂件中读取数据?
如果你想从⽂件中读取数据,可以使⽤”OPEN DATASET“ 和”READ DATASET 语句.  只要⽤户有更改权限,这个语句就能以“读取/更新”模式打开⽂件。
如果⽤户没有更改权限,⽂件只以'读取'模式打开。如果这仍然不能打开⽂件,错误信息就会出现。
下⾯的代码范例显⽰如何打开⼀个⽂件,⼀⾏⾏读出数据,并保存数据到⼀个内部表中。
代码范例
DATA: input_file(40) TYPE c,itab(94) OCCURS 0 WITH HEADER LINE,msg(100).OPEN DATASET input_file FOR INPUT IN TEXT MODEENCODING DEFAULT MESSAGE msg.IF sy-
subrc NE 0.  WRITE:/ 'ERROR opening file', input_file, 'with message',ELSE.  DO.    READ DATASET input_file INTO itab.    IF sy-
subrc = 0.      APPEND itab.    ENDIF.  ENDDO.  CLOSE DATASET input_file.ENDIF.
如何到⼀个⽂件中填写数据?
如果你需要保存数据到⼀个⽂件中,你可以使⽤“OPEN DATASET”
对于OUTPUT的语句,只要⽤户有⽂件读取的授权,此语句试图以'写/更新'模式打开⽂件。如果⽤户没有授权,系统中打开'写'模式⽂件。
如果该⽂件已存在,其现有的内容被删除。
如果该⽂件不存在,系统会创建⼀个新⽂件。
代码范例通过循环(LOOP)从内表中读取数据,然后⼀⾏⾏地转移到⽂件中。
代码范例
DATA: output_file(40) TYPE c,itab(94) OCCURS 0 WITH HEADER LINE,msg(100).OPEN DATASET output_file FOR OUTPUT IN TEXT MODEENCODING DEFAULT MESSAGE msg.IF sy-
subrc EQ 0.  LOOP AT itab.    TRANSFER itab TO output_file.  ENDLOOP.  CLOSE DATASET output_file.ELSE.  WRITE:/ 'ERROR: Writing file with message', msg.ENDIF.
如何将数据加到⼀个⽂件的尾部?
前⾯的范例是把数据加到⼀个⽂件中。
如果⽂件在系统中存在,旧的内容会被删除然后加进新的数据。但在很多情况下,
你不想清除现有的内容。
你只是想追加新的内容到⽂件的末尾。
要做到这⼀点,你可以使⽤“ FOR APPENDING“语句. 这个语句
会试图打开⽂件成”追加'模式,然后你可以把新的数据加到⽂件的末尾。
代码范例
如何使你的⽂件I / O程序可以在不同的操作系统下运⾏?
正如你在下⾯的例⼦中看到,你需要提供⼀个逻辑⽂件名和所属操作系统的名称,从⽽获得实时的物理⽂件名。
If you don't specify the operating system, the function module will use system defined operating system name, sy-opsys, by default. 如果你不指定操作系统,功能模块将使⽤系统定义的默认操作系统的名(SY - 代码范例
DATA: lv_filenam TYPE string.CALL FUNCTION 'FILE_GET_NAME'EXPORTING*  CLIENT                      = SY-MANDTlogical_filename            = '<file_name>'*  OPERATING_SYSTEM            = SY-
OPSYS*  PARAMETER_1                  = ' '*  PARAMETER_2                  = ' '*  PARAMETER_3                  = ' '*  USE_PRESENTATION_SERVER      = ' '*  WITH_FILE_EXTENSION          = ' '*  USE_BUFFER                进⼝*  EMERGENCY_FLAG              =*  FILE_FORMAT                  =file_name                    = lv_filenamEXCEPTIONSfile_not_found              = 1OTHERS                      = 2.IF sy-subrc <> 0.* MESSAGE ID SY-MSGID T MSGV1 SY-MSGV2 SY-MSGV3 SY-MSGV4.ENDIF.
如何在ABAP程序⾥运⾏Windows /Unix命令?
如果你是⼀个Unix或Windows操作系统,下⾯的代码范例显⽰如何在该操作系统上运⾏命令。
该机制其实就是打开⼀个⽂件,运⾏命令。然后将运⾏结果写⼊⼀个⽂件。
代码范例显⽰了如何运⾏的Unix命令。
如果你在Windows系统上,你只需把⽂件的路径和命令更改成Windows格式。
代码范例
DATA: result_file(50) VALUE '/tmp/test',msg_text(50),command(255) VALUE 'ls'.OPEN DATASET result_file FOR OUTPUT IN TEXT MODE ENCODING DEFAULTFILTER command MESSAGE msg_text.CLOSE 如何从应⽤服务器(Application Server)上检索到⽂件列表?
使⽤功能模块“RZL_READ_DIR_LOCAL”,你可以从应⽤服务器上得到给定的⽂件⽬录中的⽂件列表。
下⾯的代码范例显⽰了如何从当前⽬录检索⽂件列表。
代码范例:
DATA: lv_fdir TYPE pfeflnamel VALUE '.',it_files LIKE salfldir OCCURS 0 WITH HEADER LINE.CALL FUNCTION 'RZL_READ_DIR_LOCAL'  EXPORTING    name    = lv_fdir  TABLES    file_tbl = it_files.LOOP AT name.ENDLOOP.
2.4其他有⽤的建议
如何转换不同的时区的⽇期和时间?
⽇期和时间的转换可以通过先转换⽇期和时间到格林尼治标准时区(GMT),然后从格林尼治时区的⽇期和时间转换到所需时区的⽇期和时间。
⾸先,你可以使⽤功能模块“IB_CONVERT_INTO_TIMESTAMP”转换⽇期和时间到GMT时区。输⼊参数是⽇期,时间和时区。输出参数就是格林尼治时间。
然后,你使⽤功能模块“IB_CONVERT_FROM_TIMESTAMP”再转换⽇期和时间到你所需的时区。
输⼊参数是从上⾯的功能模块获得时间和所需转换的时区。输出参数是需要的时区的⽇期和时间。
Please note some related system fields here.
请注意⼀些相关的系统域值。
域值SY -DATUM和SY - UZEIT分别是系统的⽇期和时间。
如果你需要得到本地⽇期,时间,⽽所在时区,你可以分别使⽤域值SY - DATLO,SY - TIMLO与SY - ZONLO。
代码范例DATA :timestamp LIKE tzonref-tstamps,time    LIKE sy-uzeit,date    LIKE sy-datum.time = sy-uzeit.date = sy-datum.WRITE :/ 'Current system Date and Time is ',date, time.WRITE :/ 'Current system located a zonlo.CALL FUNCTION 'IB_CONVERT_INTO_TIMESTAMP'  EXPORTING    i_datlo    = date    i_timlo    = time    i_tzone    = sy-
zonlo  IMPORTING    e_timestamp = timestamp.CALL FUNCTION 'IB_CONVERT_FROM_TIMESTAMP'  EXPORTING    i_timestamp = timestamp    i_tzone    = 'PST'  IMPORTING    e_datlo    = date    e_timlo    = 如何使⽤Field Symbols?
在ABAP⾥,Field symbol就像是C语⾔⾥的指针。它有⼀个参考值指向内部表记录
或⼀个变量。它的本⾝不包含任何数据。
Field Symbol的最⼤优点就是灵活性。它不关⼼指向数据是什么类型。当然它的不
利之处也是由于这种灵活性。编译器不检查field symbol的类型。由于没有类型检
查,编译器⼏乎不可能在运⾏前检测到错误。
field symbol的语法是它总是由尖括号括起来。ASSIGN命令⽤于把变量或内部表记
录分配给field symbol。
语法
FIELD-SYMBOLS <fs>.
代码范例
DATA: itab TYPE TABLE OF spfli,wa LIKE LINE OF itab.* 传统的⽅法更新内部表
的记录。* 1. 把记录读⼊⼯作区* 2. 在⼯作区⾥改值。* 3. 从⼯作区修改内部表的记
录。READ TABLE itab INTO wa INDEX 3.wa-
carrid = 'AA'.MODIFY itab FROM wa INDEX 3.*使⽤field symbol修改内部表的记
录。FIELD-SYMBOLS <fs>.READ TABLE itab ASSIGNING <fs>.<fs>-carrid= 'AA'.
什么是系统域值(System Field)?
系统域值提供了极其有⽤的系统运⾏时的数据。系统域值的语法是SY -《名称》,
如SY - SUBRC。
系统域值的总数超过170,其中包括曾经⼀些现在已经过时系统域值。为了你的⽅
便,我在这⾥给出⼀个常常在我们的⽇常⼯作中使⽤的系统域值列表。
SY-SYSID – 正在使⽤的R / 3系统的名字。
SY-DYNNR – 屏幕数字。在对话程序中,你可以使⽤此系统域值来确定你需
要的屏幕。语法是“ LEAVE TO SCREEN SY-DYNNR.”。
SY-LANGU - ⽤户的登录语⾔(⼀个字节),例如英语是E和德语是D。
SY-MANDT – 你所在的系统客户端号。
SY-UNAME – 你的系统⽤户名。
SY-DATLO – ⽤户的本地⽇期。
SY-DATUM – 当前服务器的⽇期。
SY-TIMLO – ⽤户的本地时间。
SY-TCODE – ⽬前的交易(Transaction)代码。
SY-ULINE/VLINE – ⽔平/垂直的屏幕输出线。
SY-INDEX - 在DO或WHILE循环,SY-INDEX给出⽬前通过循环数
SY-TABIX – 当前内部表⾏号。
SY-DBCNT – 当前“select … from …”语句读到的⾏数。
SY-TFILL - 当运⾏完“DESCRIBE TABLE“或”LOOP AT“或”READ
TABLE”后, SY - TFILL给出内部表的总⾏数⽬
SY-UCOMM – ⽤户命令。你可以到菜单 “系统》状态...“去查SY_UCOMM
值。
如果我只能在运⾏期间得到数据库表名,我该如何在运⾏时动态地指定数据库表名?
下⾯的代码范例显⽰了如何在SELECT语句中使⽤数据库表名变量。
在运⾏时,程序先获取数据库表的名称- SFLIGHT,并把该数据库表的名称赋予⼀个变量- <tablename>。
在稍后的SELECT语句中,使⽤这个数据库表名称的变量。
请注意,在SQL语句⾥,变量必须放在括号⾥。
代码范例
DATA: tablename TYPE tabname16,rows TYPE i.tablename = 'SFLIGHT'.SELECT COUNT(*) FROM (tablename) INTO rows.WRITE: rows.
如何在多个程序中搜索特定的字符串?
在某些情况下,你需要在某些程序⾥寻特定的字符串。这⾥⼏个搜索的办法。
1.使⽤程序“RPR_ABAP_SOURCE_SCAN”。然⽽,在4.6C及更⾼版本,这⼀程
序不再适⽤。
2.如果你不到上⾯的程序,试试程序RSRSCAN1。不幸的是,这⼀程序在新的
NetWeaver 6.20平台上也过时了。
3.还有另⼀种⽅便的⽅法可以在某些程序字符串搜索。在transaction SE38的第⼀
个屏幕,进⼊菜单 “实⽤程序”》在源代码中查“。
如何解开压缩域值(packed field)?
下⾯的代码范例显⽰了如何解开压缩域值,并包在域值前置零。压缩域值“p_field”打印出“123”。解压缩后的域值“unp_field”打印出“00000123”。
代码范例
DATA: p_field(2) TYPE p VALUE 123,unp_field(8) TYPE c.WRITE: 'packed filed: ', p_field.UNPACK p_field TO unp_field.WRITE: / 'unpacked field: ', unp_field.打印结果
packed filed: 123
unpacked field: 00000123
如何显⽰Domain Fixed Value的简短⽂字?
你可以通过运⾏transaction SE16来打开表视图(Table View)DD07V。然后根据
Domain (DOMNAME),固定值(DOMVALUE_L)和语⾔(DDLANGUAGE)来
搜索简短⽂字(DDTEXT)。
第三章数据库表
如何数据库表选择数据?
select a  b  into (l_a, l_b) from <db_table> where c = 'XXX'.
If sy-subrc = 0.如果型号:SY - subrc = 0。
it_tab_wa-a = l_a. it_tab_wa - 1 = l_a。
it_tab_wa-b = l_b. it_tab_wa -⼄= l_b。
append it_tab_wa to it_tab. 追加it_tab_wa的it_tab。
clear it_tab_wa. 明确it_tab_wa。
Else. 其他的。
Exit. 退出。
Endif. Endif。
endselect. endselect。
Sy-dbcnt gives number of lines read from “select” 翟思dbcnt提出了⼀些“⾏数选择
阅读”
Where <f> [not] between <g1> and <g2> 如果<f> [不]和<g2>之间<g1>
Where <f> [not] like <g1> ('_' a single char. '%' any char. string including empty. 如
果<f> [不]喜欢<g1>('_'⼀个单⼀的字符。'%'的任何字符。串包括空。
<f> [not] in (<g1>, …, <gn>) <f> [不]在(<g1>,...,<gn>)
<f> is [not] NULL <f>是[不]空
* name and field type in <it_tab> match <db_table> *名和字段类型<it_tab>⽐赛<db_table>
Select a b Into (appending) corresponding fields of table it_tab
from <db_table> 从<db_table>
where c = 'XXX'. 其中c ='三⼗'。
Select ab 选择抗体
into (appending) table it_tab 成(附加)表it_tab
from <db_table> 从<db_table>

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。