经过了一个多星期的培训,在这里总结下ABAP入门的知识。由于网上关于SAP ABAP开发相关入门资料太少,关键很多都是跳过讲解的,导致很多人都浅尝辄止,下面我写的入门基础知识大部分人都能看得懂,我都会一一去解释。废话不多说进入正题。(第一次写,后续我会继续完善和更新,有什么好的建议和问题记得留言私信 我都会回复。)
一、 定义变量和赋值
输出结果:
二、 自定义类型
它的作用用于创建内表和结构,后面会讲到相关含义,这个比较重要。
types关键字用于定义类型,而data关键字用于定义变量,相当于实例化。Type后面接着的是类型,lifnr TYPE lfa1-lifnr 它的意思是字段lifnr 类型是数据库表lfa1中lifnr字段的类型一样。
后面进入se11可以看到这张表,或者双击也是可以的。se38是写程序的地方。以上内容是在se38写的。
Standard [0*3]他的意思是0条数据 3个字段
Lt_test2 ls_test 分别是定义是lty_test字段一样的内表和结构。
Lty_lfa1_2类型中包含数据库表lfa1所有字段加上char类型的zflag字段。
Type和like的区别
Type后面接的是类型而like后面接的是变量,记住这个后面经常用到。
三、 内表
内表的定义
先定义一个类型然后我们这样写
内表分为三种,第一种是标准表,第二种是排序表,第三种是哈希表。
四、 选择屏幕
这一款相当于我们以前写的UI前端页面,主要是要自己感受,下面我放两个示例好好感受。
示例1:
TABLES:sflight. "用到哪张表 声明一下
SELECTION-SCREEN BEGIN OF BLOCK bk1 WITH FRAME TITLE TEXT-001."双击text-001
SELECTION-SCREEN SKIP 2.
PARAMETERS:p_connid TYPE sflight-connid, "范围 searchhelp
p_carrid TYPE sflight-carrid.
SELECTION-SCREEN END OF BLOCK bk1.
SELECTION-SCREEN BEGIN OF BLOCK bk2 WITH FRAME TITLE TEXT-002.
SELECTION-SCREEN SKIP 1.
SELECT-OPTIONS: s_connid FOR sflight-connid OBLIGATORY,"必须填充内容
s_plane FOR sflight-planetype NO-EXTENSION,"非必填
s_curren FOR sflight-currency NO-DISPLAY,"不显示
s_price FOR sflight-price NO INTERVALS."没有间隔
SELECTION-SCREEN END OF BLOCK bk2.
SELECTION-SCREEN BEGIN OF BLOCK bk3 WITH FRAME TITLE TEXT-003.
SELECTION-SCREEN SKIP 2.
PARAMETERS:p_ckbox TYPE char1 AS CHECKBOX,
p_ckbox1 TYPE char1 AS CHECKBOX DEFAULT 'X',
p_ckbox2 TYPE char1 AS CHECKBOX,
p_ckbox3 TYPE char1 AS CHECKBOX.
SELECTION-SCREEN END OF BLOCK bk3.
SELECTION-SCREEN BEGIN OF BLOCK bk4 WITH FRAME TITLE TEXT-004.
SELECTION-SCREEN SKIP 1.
PARAMETERS: p_rb RADIOBUTTON GROUP rg,
p_rb1 RADIOBUTTON GROUP rg DEFAULT 'X',
p_rb2 RADIOBUTTON GROUP rg,
p_rb3 RADIOBUTTON GROUP rg,
p_rb4 RADIOBUTTON GROUP rg.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS p_ckbox4 TYPE char1 AS CHECKBOX.
SELECTION-SCREEN COMMENT 3(10) TEXT-005.
PARAMETERS p_ckbox5 TYPE char1 AS CHECKBOX.
SELECTION-SCREEN COMMENT 16(10) TEXT-006.
PARAMETERS p_ckbox6 TYPE char1 AS CHECKBOX.
SELECTION-SCREEN COMMENT 29(10) TEXT-007.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS: p_dwload AS CHECKBOX DEFAULT 'x'.
SELECTION-SCREEN COMMENT 5(8) TEXT-008.
PARAMETERS: p_file TYPE string.
SELECTION-SCREEN END OF LINE.
SELECTION-SCREEN END OF BLOCK bk4.
示例2:
TABLES:sflight.
SELECTION-SCREEN BEGIN OF BLOCK bk WITH FRAME TITLE TEXT-001.
PARAMETERS: p_carrid TYPE sflight-carrid OBLIGATORY,
p_connid TYPE sflight-connid.
SELECTION-SCREEN SKIP 1.
SELECT-OPTIONS: s_carrid FOR sflight-carrid,
s_connid FOR sflight-connid,
s_price FOR sflight-price.
SELECTION-SCREEN END OF BLOCK bk.
SELECTION-SCREEN BEGIN OF BLOCK bk2 WITH FRAME TITLE TEXT-002.
SELECTION-SCREEN SKIP 1.
PARAMETERS:p_ckbox TYPE char1 AS CHECKBOX,
p_ckbox1 TYPE char1 AS CHECKBOX DEFAULT 'X',
p_ckbox2 TYPE char1 AS CHECKBOX.
SELECTION-SCREEN SKIP 1.
PARAMETERS:p_rb RADIOBUTTON GROUP rg ,
p_rb1 RADIOBUTTON GROUP rg,
p_rb2 RADIOBUTTON GROUP rg DEFAULT 'X',
p_rb3 RADIOBUTTON GROUP rg.
SELECTION-SCREEN END OF BLOCK bk2.
SELECTION-SCREEN BEGIN OF LINE.
PARAMETERS p_chk TYPE char1 AS CHECKBOX.
SELECTION-SCREEN COMMENT 3(10) TEXT-003.
PARAMETERS p_chk1 TYPE char1 AS CHECKBOX DEFAULT 'X'.
SELECTION-SCREEN COMMENT 16(10) TEXT-004.
SELECTION-SCREEN END OF LINE.
如果有未定义的文本变量需要自己双击然后进行创建和修改。
五、 事件顺序
INITIALIZATION.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR s_curren-low.
PERFORM frm_value_request_currency.
AT SELECTION-SCREEN OUTPUT."隐藏必须
* PERFORM frm_modify_screen.
AT SELECTION-SCREEN."权限校验和数据校验
START-OF-SELECTION."取数
END-OF-SELECTION."清空变量
这个自己打好断点去调试 记住每个事件的执行顺序,后期改别人的项目才能知道哪里入手。
插播题外话,也是很关键的写一个报表的框架拿到FS
1.选择屏幕 2.取数 3.循环 4.内表 5.在alv显示
六、 结构和内表
前面虽然说讲了结构和内表了,现在有补充。如何用loop循环读内表和把结构添加到内表中。
TYPES: BEGIN OF ly_str,
fied(3) TYPE c,
fied1 TYPE n,
fied2 TYPE p DECIMALS 2,
END OF ly_str.
DATA: lt_str TYPE STANDARD TABLE OF ly_str,
ls_str TYPE ly_str.
CLEAR ls_str.
ls_str-fied = 'as2'.
ls_str-fied1 = '123'.
ls_str-fied2 = '12.36'.
APPEND ls_str to lt_str.
CLEAR ls_str.
ls_str-fied = 's22'.
ls_str-fied1 = '345'.
ls_str-fied2 = '65.33'.
APPEND ls_str to lt_str.
CLEAR ls_str.
ls_str-fied = 'sd3'.
ls_str-fied1 = '644'.
ls_str-fied2 = '96.88'.
APPEND ls_str to lt_str.
LOOP AT lt_str into ls_str.
BREAK-POINT.
ENDLOOP.
读内表是一行行的把数据传给结构的,内表可以存多行数据但是结构是能存一条结构。变量用之前都要清除一下,不然会一直保存着。
示例2
TYPES:BEGIN OF ty_ekko,
ebeln TYPE ekko-ebeln,
bukrs TYPE ekko-bukrs,
absgr TYPE ekko-absgr,
END OF ty_ekko.
DATA: ls_ekko TYPE ty_ekko,
lt_ekko TYPE STANDARD TABLE OF ty_ekko,
lt_ekko2 TYPE STANDARD TABLE OF ty_ekko.
CLEAR ls_ekko.
ls_ekko-ebeln = '450000'.
ls_ekko-bukrs = 'F000'.
ls_ekko-absgr = '00'.
APPEND ls_ekko TO lt_ekko.
CLEAR ls_ekko.
ls_ekko-ebeln = '450001'.
ls_ekko-bukrs = 'F001'.
ls_ekko-absgr = '01'.
APPEND ls_ekko TO lt_ekko.
CLEAR ls_ekko.
ls_ekko-ebeln = '450002'.
ls_ekko-bukrs = 'F002'.
ls_ekko-absgr = '02'.
APPEND ls_ekko TO lt_ekko.
CLEAR ls_ekko.
ls_ekko-ebeln = '450003'.
ls_ekko-bukrs = 'F003'.
ls_ekko-absgr = '03'.
APPEND ls_ekko TO lt_ekko.
CLEAR ls_ekko.
ls_ekko-ebeln = '450004'.
ls_ekko-bukrs = 'F004'.
ls_ekko-absgr = '04'.
APPEND ls_ekko TO lt_ekko2.
CLEAR ls_ekko.
ls_ekko-ebeln = '450005'.
ls_ekko-bukrs = 'F005'.
ls_ekko-absgr = '05'.
APPEND ls_ekko TO lt_ekko.
APPEND LINES OF lt_ekko to lt_ekko2.
BREAK-POINT.
意思是把lt_ekko 里面的数据赋值到lt_ekko2中。
示例4
LOOP AT lt_ekko INTO ls_ekko.
DELETE lt_ekko INDEX SY-TABIX .
WRITE: / SY-TABIX.
BREAK-POINT.
ENDLOOP.
输出几个一,以为它都是删除索引值为一的数据,也就是删了第一行,下面的数据向上顶,他们新的索引值是他们以前的索引值减一。
示例5:
CLEAR ls_ekko.
READ TABLE lt_ekko INTO ls_ekko WITH KEY ebeln = '450001'.
BREAK-POINT.
读取内表数据.
示例6:
SORT lt_ekko BY ebeln ASCENDING.
BREAK-POINT.
READ TABLE lt_ekko TRANSPORTING NO FIELDS WITH KEY ebeln = '450008' BINARY SEARCH.
IF sy-subrc = 0.
WRITE: '找到相关数据'.
ELSE.
WRITE: '未找到相关数据'.
ENDIF.
Sy-subrc = 0他的意思是找到相关的数据。
七、 AT END OF
AT END OF他只在loop循环中起作用,他的作用是读取相同字段下最后一行数据,什么意思呢,下面结合示例来讲,它用于数据的统计。用之前一般要进行排序,默认是升序。
TYPES: BEGIN OF ty_mard,
matnr TYPE mard-matnr,
werks TYPE mard-werks,
insme TYPE mard-insme,
END OF ty_mard.
DATA: ls_mard TYPE ty_mard,
lt_mard TYPE STANDARD TABLE OF ty_mard.
CLEAR ls_mard.
ls_mard-matnr = 'M1'.
ls_mard-werks = '0001'.
ls_mard-insme = 1.
APPEND ls_mard TO lt_mard.
CLEAR ls_mard.
ls_mard-matnr = 'M1'.
ls_mard-werks = '0002'.
ls_mard-insme = 2.
APPEND ls_mard TO lt_mard.
CLEAR ls_mard.
ls_mard-matnr = 'M2'.
ls_mard-werks = '0003'.
ls_mard-insme = 3.
APPEND ls_mard TO lt_mard.
CLEAR ls_mard.
ls_mard-matnr = 'M2'.
ls_mard-werks = '0004'.
ls_mard-insme = 4.
APPEND ls_mard TO lt_mard.
CLEAR ls_mard.
ls_mard-matnr = 'M2'.
ls_mard-werks = '0005'.
ls_mard-insme = 5.
APPEND ls_mard TO lt_mard.
DATA: ls_mard_tmp LIKE ls_mard,
lt_mard_sum LIKE lt_mard,
l_insme TYPE mard-insme.
LOOP AT lt_mard INTO ls_mard.
ls_mard_tmp = ls_mard.
l_insme = l_insme + ls_mard-insme.
AT END OF matnr.
ls_mard_tmp-insme = l_insme.
APPEND ls_mard_tmp TO lt_mard_sum.
CLEAR l_insme.
ENDAT.
ENDLOOP.
BREAK-POINT.
这是入门的写法
下面是做项目的写法:
SORT lt_mard BY matnr.
LOOP AT lt_mard ASSIGNING FIELD-SYMBOL().
l_insme = l_insme + -insme.
AT END OF matnr.
-insme = l_insme.
APPEND TO lt_mard_sum.
BREAK-POINT.
CLEAR: ,
l_insme.
ENDAT.
ENDLOOP.
八、 取数
学过mysql的人再学opensql是比较简单的。下面直接来示例。
TYPES: BEGIN OF ty_ekpo,
ebeln TYPE ekpo-ebeln,
ebelp TYPE ekpo-ebelp,
menge TYPE ekpo-menge,
END OF ty_ekpo.
DATA: lt_ekpo TYPE STANDARD TABLE OF ty_ekpo,
LS_EKKO LIKE LT_EKPO,"table
LS_EKKO2 LIKE LINE OF LT_EKPO.
BREAK-POINT.
SELECT ebeln
ebelp
menge
FROM ekpo
INTO CORRESPONDING FIELDS OF TABLE lt_ekpo
WHERE ebeln IN ('4500000024', '4500000030', '4500000038','4500000059').
九、 move-corresponding
TYPES: BEGIN OF ty_str,
field TYPE char10,
field2 TYPE i,
field3 TYPE p DECIMALS 2,
END OF ty_str.
TYPES: BEGIN OF ty_str2,
field TYPE char10,
field2 TYPE i,
field3 TYPE CHAR10,
END OF ty_str2.
DATA: ls_str TYPE ty_str.
DATA: ls_str2 TYPE ty_str2.
ls_str-field = 'A'.
ls_str-field2 = '1'.
ls_str-field3 = '0.11'.
MOVE-CORRESPONDING ls_str TO ls_str2."把ls_str全部值赋到ls_str2
它的用法是把字段值全部赋值到另一个字段中,字段顺序无所谓,它会自动选择匹配。
十、 COLLECT
TYPES: BEGIN OF ty_str,
field TYPE char10,
field2 TYPE i,
field3 TYPE p DECIMALS 2,
* field4 type num5,
END OF ty_str.
DATA: ls_str TYPE ty_str,
lt_str TYPE STANDARD TABLE OF ty_str.
CLEAR ls_str.
ls_str-field = 'A'.
ls_str-field2 = '1'.
ls_str-field3 = '0.11'.
*ls_str-field4 = '9'.
COLLECT ls_str INTO lt_str.
CLEAR ls_str.
ls_str-field = 'A'.
ls_str-field2 = '2'.
ls_str-field3 = '1'.
*ls_str-field4 = '11'.
COLLECT ls_str INTO lt_str.
CLEAR ls_str.
ls_str-field = 'A'.
ls_str-field2 = '3'.
ls_str-field3 = '1'.
*ls_str-field4 = '12'.
COLLECT ls_str INTO lt_str.
CLEAR ls_str.
ls_str-field = 'B'.
ls_str-field2 = '10'.
ls_str-field3 = '1'.
*ls_str-field4 = '9'.
COLLECT ls_str INTO lt_str.
BREAK-POINT.
它的用法是COLLECT 以非数值类型的字段为主键,合计数值类型的字段的值。运算结果如下:
数值类型只有p和I,相信很多人都会认为n也是数值类型,其实他是char类型来的,是非数值类型。我们把fied4的注释给放开,我们的主键就有fied1和fied4了,他们完全一样的情况下才会是同一类,任意一个不一样都不是同一类,我们看看运行结果:
现在我们看到的是四组数据,他们并没有进行数据的合计。
十一、取数
1.抽取单个字段
DATA:lv_ebeln TYPE ekko-ebeln.
SELECT SINGLE ebeln
INTO lv_ebeln
FROM ekko
WHERE ebeln = '4500000001'.
IF sy-subrc = 0
WRITE:/ lv_ebeln.
ELSE.
WRITE:/ '没有找到相关数据。'.
ENDIF.
BREAK-POINT.
运行结果如下:
TYPES:BEGIN OF lty_ekko,
ebeln TYPE ekko-ebeln,
bukrs TYPE ekko-bukrs,
bstyp TYPE ekko-bstyp,
statu TYPE ekko-statu,
END OF lty_ekko.
DATA:LS_EKKO TYPE LTY_EKKO.
SELECT SINGLE BSTYP
BUKRS
INTO (LS_EKKO-BSTYP,
LS_EKKO-BUKRS)
FROM EKKO
WHERE EBELN = '4500000001'.
IF SY-SUBRC = 0.
WRITE:/ SY-SUBRC.
ELSE.
WRITE: /'NO FOUND.'.
ENDIF.
BREAK-POINT.
这个比较少用,大家记住抽取多个字段into后面是用小括号就行。
3.别名AS(了解就好)
TYPES:BEGIN OF lty_ekko,
ebeln TYPE ekko-ebeln,
bukrs TYPE ekko-bukrs,
zfiedld TYPE ekko-bstyp,
END OF lty_ekko.
DATA:ls_ekko TYPE lty_ekko.
SELECT SINGLE ebeln
bukrs
bstyp AS zfield
INTO CORRESPONDING FIELDS OF ls_ekko
FROM ekko
WHERE ebeln = '4500000001'.
4.抽取多行数据到内表
TYPES:BEGIN OF lty_ekko,
ebeln TYPE ekko-ebeln,
bukrs TYPE ekko-bukrs,
bstyp TYPE ekko-bstyp,
statu TYPE ekko-statu,
END OF lty_ekko.
DATA:lt_ekko TYPE STANDARD TABLE OF lty_ekko.
SELECT ebeln
bstyp
bukrs
statu
INTO CORRESPONDING FIELDS OF TABLE lt_ekko
FROM ekko
WHERE ebeln IN ('4500000024','4500000030','500000038').
BREAK-POINT .
5.动态取数
这个名字听上去很高大上,其实就加个if判断,别被吓着就可以了,直接上代码。
DATA:lt_ekko TYPE STANDARD TABLE OF lty_ekko,
lv_falg TYPE char1,
lv_where TYPE string.
IF lv_falg = 'X'.
lv_where = 'ebeln = ''4500000024'' '.
ELSE.
lv_where = 'ebeln = ''4500000038'' '.
ENDIF.
SELECT ebeln
bstyp
bukrs
statu
INTO CORRESPONDING FIELDS OF TABLE lt_ekko
FROM ekko
WHERE (lv_where).
BREAK-POINT.
6.表连接
TYPES:BEGIN OF lty_ekko,
ebeln TYPE ekko-ebeln,
bukrs TYPE ekko-bukrs,
ebelp TYPE ekpo-ebelp,
statu TYPE ekpo-statu,
END OF lty_ekko.
DATA:lt_ekko TYPE STANDARD TABLE OF lty_ekko.
SELECT ekko~ebeln
ekko~bukrs
ekpo~ebelp
ekpo~statu
FROM ekko JOIN ekpo
ON ekko~ebeln = ekpo~ebeln
INTO CORRESPONDING FIELDS OF TABLE lt_ekko
WHERE ekko~ebeln = '4500000059'.
我们先创建一个内表来存放读取的数据,ekko和ekpo这两张表进行连接,通过ekko~ebeln = ekpo~ebeln他们的主键进行匹配,然后再用corresponding赋值到内表中,他的搜索条件是where后面。
十二、for all entries in
TYPES:BEGIN OF lty_ekpo,
ebeln TYPE ekpo-ebeln,
ebelp TYPE ekpo-ebelp,
bukrs TYPE ekpo-bukrs,
aedat TYPE ekpo-aedat,
END OF lty_ekpo.
DATA:ls_ekpo TYPE lty_ekpo,
lt_ekpo TYPE STANDARD TABLE OF lty_ekpo,
lt_ekpo_tmp TYPE STANDARD TABLE OF lty_ekpo.
ls_ekpo-ebeln = '4500000030'.
APPEND ls_ekpo TO lt_ekpo_tmp.
IF lt_ekpo_tmp IS NOT INITIAL.
SELECT ebeln
ebelp
bukrs
aedat
INTO CORRESPONDING FIELDS OF TABLE lt_ekpo
FROM ekpo
FOR ALL ENTRIES IN lt_ekpo_tmp
WHERE ebeln = lt_ekpo_tmp-ebeln.
ENDIF.
用FOR ALL ENTRIES IN 一般都要与if连用,因为不做if判断如果内表lt_ekpo为空的话它会把所有的数据都查出来,这样会很大程度上影响性能。我们来看看运行的结果。
Lt_ekpo只有一个字段有值。
相信很多人都不明白为什么要这样取数呢(新手),我也问过老师大概意思是说后面的业务有关,我就把疑问停留在这里了,慢慢再去解决。
后续会更新变量是如何命名的。