基本语法
抑制空白NO-ZERO
例:
输出
定义类型
DATA LV_NUM TYPE N LENGTH 10.
DATA LV_NUM2(10) TYPE N.
输出是一样的
帮助文档
使用F1
空白行
SKIP."跳过一行
SKIP 3."跳过三行
SKIP TO LINE 2.是跳转到第2行的意思
例如:
WRITE: / 'This is line 1'.
WRITE: / 'This is line 2'.
SKIP TO LINE 10. " 跳转到第10行
WRITE: / 'This is line 5'.
输出
SKIP TO LINE 10 意思是:跳转到第10行之后,在输出This is line 5,其中练习1和下划线也各算一行,所以他俩总共占两行
消息Message
MESSAGE <message_type> <message_class> <message_number> [WITH <field1> <field2> ...].
<message_type>
:消息类型,可以是以下值:I
:信息(Information)W
:警告(Warning)E
:错误(Error)S
:成功(Success)A
:中止(Abort)X
:退出(Exit)
<message_class>
:消息类(例如ZMSG
)。<message_number>
:消息编号(例如001
)。WITH <field1> <field2> ...
:可选参数,用于替换消息文本中的占位符&1
,&2
,&3
,&4
。例
1. 显示简单消息
MESSAGE 'Hello, World!' TYPE 'I'.
输出:
- 如果是 MESSAGE 'HELLO,WORLD' TYPE 'E'.
- 则输出
其他的也是按照类型来
-
2. 使用消息类和消息编号
假设在消息类
ZMSG
中定义了消息编号001
,内容为"This is a test message"
。MESSAGE I001(ZMSG).
输出:
-
例如This is a test message
- 输出:
-
3. 使用占位符
假设消息编号
002
的内容为"The value of &1 is &2"
。DATA: lv_value1 TYPE string VALUE 'X', lv_value2 TYPE string VALUE '10'. MESSAGE I002(ZMSG) WITH lv_value1 lv_value2.
输出:
The value of X is 10
4. 处理错误消息
如果程序执行过程中发生错误,可以使用
E
类型消息终止程序:IF sy-subrc <> 0. MESSAGE E003(ZMSG) WITH 'Error occurred'. ENDIF.
输出:
Error occurred
5. 显示警告消息
MESSAGE W004(ZMSG) WITH 'Warning: Data incomplete'.
输出:
Warning: Data incomplete
6. 显示成功消息
MESSAGE S005(ZMSG) WITH 'Operation completed successfully'.
输出:
Operation completed successfully
- MESSAGE'hello world' TYPE 'I'.
- 输出结果为
- MESSAGE'hello world' TYPE 'I' DISPLAY LIKE 'W'.
- 输出结果为
消息类型的行为
I
(信息):显示消息后,程序继续执行。W
(警告):显示消息后,程序继续执行,但用户需要确认。E
(错误):显示消息后,程序终止执行。S
(成功):显示消息后,程序继续执行。A
(中止):显示消息后,程序终止执行,并返回初始屏幕。X
(退出):显示消息后,程序终止执行,并抛出短转储(Short Dump)。
自定义消息
- 使用 T-code
SE91
创建消息类。 - 在消息类中定义消息编号和消息文本。
- 在程序中使用
MESSAGE
语句引用消息。
如果指定message-id,则可以直接写MESSAGE I000.就可以显示与MESSAGE I000(ZITO4700)一样的效果。
MESSAGE I002(ZMSG) DISPLAY LIKE 'E'.
输出
基础数据类型
数值类型
数据类型 | 描述 | 示例 |
---|---|---|
I | 整数(Integer),4 字节 | DATA num TYPE I. |
F | 浮点数(Float),8 字节 | DATA num TYPE F. |
P | 打包数(Packed Number),用于精确计算 | DATA num TYPE P LENGTH 8 DECIMALS 2. |
DECFLOAT16 | 十进制浮点数,16 字节 | DATA num TYPE DECFLOAT16. |
DECFLOAT34 | 十进制浮点数,34 字节 | DATA num TYPE DECFLOAT34. |
字符类型
数据类型 | 描述 | 示例 |
---|---|---|
C | 字符(Character),固定长度 | DATA name TYPE C LENGTH 10. |
STRING | 字符串(String),可变长度 | DATA name TYPE STRING. |
N | 数字字符(Numeric Character) | DATA code TYPE N LENGTH 5. |
日期和时间类型
数据类型 | 描述 | 示例 |
---|---|---|
D | 日期(Date),格式为 YYYYMMDD | DATA date TYPE D. |
T | 时间(Time),格式为 HHMMSS | DATA time TYPE T. |
UTCLONG | UTC 时间戳,高精度 | DATA timestamp TYPE UTCLONG. |
布尔类型
数据类型 | 描述 | 示例 |
---|---|---|
ABAP_BOOL | 布尔值(Boolean),ABAP_TRUE 或 ABAP_FALSE | DATA flag TYPE ABAP_BOOL. |
其他类型
数据类型 | 描述 | 示例 |
---|---|---|
X | 十六进制(Hexadecimal),固定长度 | DATA hex TYPE X LENGTH 4. |
XSTRING | 十六进制字符串,可变长度 | DATA hex TYPE XSTRING. |
例1:
DATA:
LV_ID TYPE N LENGTH 4, "numeric 因为是4位,所以范围就是0000~9999
LV_NAME TYPE C LENGTH 10, "char
LV_AGE TYPE I, "integer 整数
LV_SR TYPE D. "Date 日期
LV_ID = 0000.
LV_NAME = 'JEE'.
LV_AGE = 20.
LV_SR = '20250311'.
WRITE: / LV_NAME,
/ LV_ID,
/ LV_AGE,
/ LV_SR.
输出:
如果日期格式不对,可以在
输入SU01,输入用户之后
点击眼镜标志,在这里查看日期格式
更改用户参数
为什么I类型不需要写length?
在 ABAP 中,I
类型(Integer,整数)是预定义的基本数据类型,它的长度是固定的,因此不需要显式指定长度。以下是详细解释:
1. I
类型的固定长度
I
类型表示一个4 字节(32 位)的有符号整数。它的取值范围是:
- 最小值:
-2,147,483,648
- 最大值:
2,147,483,647
由于 I
类型的长度和存储格式是固定的(4 字节),因此不需要在定义时指定长度。
2. ABAP 对基本数据类型的处理
ABAP 中的基本数据类型(如 I
、F
、D
、T
等)都是预定义的,它们的长度和存储格式在 ABAP 运行时环境中已经确定。例如:
I
类型:4 字节F
类型:8 字节D
类型:8 字节(格式为YYYYMMDD
)T
类型:6 字节(格式为HHMMSS
)
因为这些类型的长度是固定的,所以不需要在定义时指定长度。
3. 需要指定长度的数据类型
ABAP 中某些数据类型的长度是可变的,因此需要在定义时指定长度。例如:
C
类型(字符):需要指定长度,如C LENGTH 10
。N
类型(数字字符):需要指定长度,如N LENGTH 5
。P
类型(打包数):需要指定长度和小数位数,如P LENGTH 8 DECIMALS 2
。
这些类型的长度由程序员根据业务需求决定,因此必须显式指定。
4. I
类型的定义示例
在 ABAP 中定义 I
类型的变量时,直接使用 TYPE I
即可,无需指定长度:
abap
DATA: num TYPE I. " 定义一个整数变量
5. 为什么 I
类型不需要长度?
- 固定长度:
I
类型的长度是固定的(4 字节),无法更改。 - 简化语法:ABAP 的设计目标之一是简化开发,因此对于固定长度的类型,不需要额外的语法来指定长度。
- 避免错误:如果允许指定长度,可能会导致不一致或错误的使用方式。
6. 与 P
类型的对比
P
类型(打包数)是一种可变长度的数据类型,它的长度和小数位数需要显式指定。例如:
abap
DATA: amount TYPE P LENGTH 8 DECIMALS 2. " 定义一个打包数变量
LENGTH 8
表示总长度为 8 字节。DECIMALS 2
表示小数位数为 2。
与 I
类型不同,P
类型的长度和精度是可配置的,因此需要显式指定。
系统变量
WRITE: /'SY-SUBRC', SY-SUBRC,"系统执行某指令后,表示成功与否的变量
/'SY-DATUM', SY-DATUM, "系统当前日期
/'SY-TABIX', SY-TABIX,"当前内表的第几行
/'SY-INDEX', SY-INDEX, "当前循环次数
/'SY-LANGU', SY-LANGU, "系统当前登录语言
/'SY-MANDT', SY-MANDT, "系统当前客户端
/'SY-TCODE', SY-TCODE, "当前事务码
/'SY-UNAME', SY-UNAME, "当前登录账号
/'SY-UZEIT', SY-UZEIT, "当前时间
/'SY-ULINE',SY-ULINE. "横线。
输出:
系统变量既是变量也是类型
可以这样写:
DATA LV_DATUM TYPE SY-DATUM.
F类型注意:
在 ABAP 中,F
类型(浮点数)的赋值确实有一些特殊的规则。你提到的代码:
DATA: float_num TYPE F.
float_num = 123.456.
会导致语法错误,这是因为 ABAP 对浮点数的赋值有一些严格的要求。以下是详细解释和正确的写法:
1. 为什么会导致错误?
在 ABAP 中,浮点数(F
类型)的赋值不能直接使用小数点(.
)来表示小数部分。这是因为 ABAP 编译器会将 .
解析为语句的结束符号,从而导致语法错误。
2. 正确的写法
为了避免错误,可以使用以下两种方式为 F
类型的变量赋值:
方法 1:使用科学计数法
在 ABAP 中,浮点数通常以科学计数法的形式表示。例如:
abap
DATA: float_num TYPE F.
float_num = '123.456'. " 使用单引号包裹
或者:
abap
DATA: float_num TYPE F.
float_num = '1.23456E+02'. " 使用科学计数法
ABAP 对浮点数的处理规则
- 小数点问题:ABAP 编译器会将
.
解析为语句的结束符号,因此不能直接使用123.456
这样的形式。 - 科学计数法:科学计数法是 ABAP 中表示浮点数的标准方式,例如
1.23E+10
。 - 单引号包裹:如果浮点数包含小数点,必须使用单引号将其包裹,以避免语法错误
默认值
DATA LV_TIME TYPE T VALUE '202001'."Time时间HHMMSS, VALUE是默认值
WRITE: / '默认时间:' ,LV_TIME.
LV_TIME = SY-UZEIT."给了默认值之后,也可以继续赋值。
WRITE: / '系统时间:' , LV_TIME.
WRITE输出
注意:
普通输出例如
WRITE / LV_NAME_STRING. 可以直接输出了
但是
WRITE: / '默认时间:' ,LV_TIME.
必须write后面加上:才可以输出,因为有了'默认时间:',而且字符串后面必须加逗号”,“才可以,否则报错
LIKE关键字
DATA <name> [length] LIKE <object>|<type> [VALUE <val>][decimals].
变量定义也可以用LIKE关键字
TYPE 与 LIKE的区别:
LIKE(类似、像)某数据类型,如系统变量,而TYPE则用在定义数据类型。
Eg:
DATA:lv_date like sy-datum.
例如
则LV_NAME_2和LV_NAME有一样的长度,一样的类型
一次性多行注释
选中代码之后,右键->格式->添加行注释 “Ctrl+,”
取消行注释同理上述操作 “Ctrl+.”
也可以自己自定义:
然后在新快捷方式中分配,如果不能分配,有可能与windows系统有冲突
这里我分配了Ctrl+shift+.
常量CONSTANTS
CONSTANTS:
LV_MALE TYPE C LENGTH 2 VALUE '男'."常量
LV_MALE = '女'. "常量是不允许修改的
常量确定之后是不允许被修改的,会报错。
Where use list
这个按钮可以快速定位到你想知道那个东西在哪里使用过
例如:我想知道LV_NAME在哪里被使用过,光标放在LV_NAME上,然后点击
就可以正常搜索到了,然后可以点击右边的LV_NAME就会跳转到那一个LV_NAME
Debug
*DATA LV_DATUM TYPE D.
DATA LV_DATUM TYPE SY-DATUM."SY-DATUM既是变量也是类型,和上面效果是一样的
LV_DATUM = SY-DATUM.
WRITE: /'当前日期是:',LV_DATUM.
LV_DATUM = LV_DATUM + 14.
WRITE: /'2周之后是:',LV_DATUM.
通过F5来下一步,右边可以看到变量变化
字符串
上面是各种字符串方法
例如:
计算长度STRLEN
为 了 找 到 字 符 串 的 长 度 , 我 们 可 以 使 用 S T R L E N 语 句 。 S T R L E N ( ) 函 数 返 回 字 符 串 中 包 含 的 字 符 数 。
REPORT YT_SEP_15.
DATA: title_1(10) VALUE 'Tutorials’,
length_1 TYPE I.
length_1 = STRLEN( title_1 ).
Write: / 'The Length of the Title is:', length_1.
输出:The Length of the Title is: 9
就算将title_1改为'Tutossssssssrials’,最后结果是10,因为length就是10,不会超过length
拼接字符串CONCATENATE
DATA:
LV_RESULT(100) TYPE C,
LV_TITLE TYPE C LENGTH 10.
LV_TITLE = 'Student'.
CONCATENATE LV_TITLE LV_NAME '0000' INTO LV_RESULT SEPARATED BY 'MMSPACE'.
WRITE: / '拼接之后的结果:',LV_RESULT.
结果:
压缩空格CONDENE
字符串查找
0为成功
字符串替换REPLACE
字符串截取
+3(4)代表:从第三个字符开始截取4个字符
字符串拆分SPLIT
结果
以*来分割
字符串移位操作SHIFT
清空变量CLEAR
LV_TITLE = LV_RESULT+3(4).
WRITE: / LV_TITLE.
WRITE:/'清空前:', LV_TITLE .
length_1 = STRLEN( LV_TITLE ).
WRITE:/ length_1.
clear LV_TITLE.
WRITE:/'清空后:', LV_TITLE .
length_1 = STRLEN( LV_TITLE ).
WRITE:/ length_1.
结果:
字符串运算符(CA,CO,CN.....)
例:
DATA: LV_P(5) TYPE C VALUE 'APPLE',
LV_Q(5) TYPE C VALUE 'CHAIR'.
IF LV_P CA LV_Q.
WRITE:/ 'P contains at least on character of Q'.
ELSE.
WRITE:/ 'False'.
ENDIF.
输出:
格式化操作
例:
DATA: n(9) TYPE C VALUE 'Tutorials',
m(5) TYPE C VALUE 'Point'.
WRITE: n, m.
WRITE: / n UNDER m, / m UNDER m.
UNDER是输出在指定的字段下面
例2:
DATA:
LV_FORMATTER TYPE C LENGTH 10.
LV_FORMATTER = '12345'.
WRITE:/ 'RIGHT-JUSTIFIED',LV_FORMATTER RIGHT-JUSTIFIED.
WRITE:/ 'LEFT-JUSTIFIED', LV_FORMATTER LEFT-JUSTIFIED.
WRITE:/ 'CENTERED', LV_FORMATTER CENTERED.
WRITE:/ LV_UZEIT USING EDIT MASK '__@__:__'.
输出:
加减乘除取余运算符
循环
PARAMETERS
PARAMETERS就是输入框,执行程序之后会弹出一个输入框然后再点击执行,才会进行下一步
例:
输入之后,点击左上角或者摁F8
while循环
DO循环
例子:
嵌套循环
例:
DATA:
LV_A1 TYPE I,
LV_B1 TYPE I.
LV_A1 = 0.
LV_B1 = 0.
DO 2 TIMES.
LV_A1 = LV_A1 + 1.
WRITE: /'Outer', LV_A1.
DO 10 TIMES.
LV_B1 = LV_B1 + 1.
WRITE: /'Inner', LV_B1.
ENDDO.
ENDDO.
每次处理外部DO 循环时,处理两次外部DO 循环并处理10 次内部DO 循环。所以在这种情况下,内循环被处理20 次。
输出:
终止循环
例:
DO 15 TIMES.
IF SY-INDEX = 6.
CONTINUE.
* EXIT.
ENDIF.
CHECK SY-INDEX <> 5.
WRITE: / 'Hello', SY-INDEX.
ENDDO.
使用了continue,所以当SY-INDEX = 6的时候跳出循环,check是不等于5的时候输出,所以输出中没有5和6,因为6被continue跳过了,5不满足条件所以不输出
IF
IF..ELSE..
IF...ELSEIF...
嵌套IF
CASE
异常
结果:
结构体
结构体数据
结构体数据只是将LW_STU作为一组数据,如果想同样的类型数据对象只能LW_STU2 LIKE LW_STU.
非常鸡肋,用起来很笨,所以有第二种方法结构体类型
DATA:
BEGIN OF LW_STU,
ID TYPE N LENGTH 4,
NAME TYPE C LENGTH 10,
AGE TYPE I,
SR TYPE D,
END OF LW_STU.
LW_STU-ID = 0000.
LW_STU-NAME = 'Peter'.
WRITE: / LW_STU-ID.
WRITE: / LW_STU-NAME.
DATA:
LW__STU2 LIKE LW_STU.
结构体类型
结构体类型就是类似于java中的类,把类型确定好了,后续我再想创建学生只需要 LW_STU2 TYPE LTY_W_STU.便可以创建一个新的学生,如果我想在学生中添加新的属性也更加方便,如果想stu2的数据和stu的一样直接 LW_STU2 = LW_STU.
TYPES:
BEGIN OF LTY_W_STU,
ID TYPE N LENGTH 4,
NAME TYPE C LENGTH 10,
AGE TYPE I,
SR TYPE I,
SCHID TYPE N LENGTH 4,
END OF LTY_W_STU.
DATA:
LW_STU TYPE LTY_W_STU.
LW_STU-ID = 2220.
LW_STU-NAME = 'Peter'.
WRITE: / LW_STU-ID.
WRITE: / LW_STU-NAME.
DATA:
LW_STU2 TYPE LTY_W_STU.
LW_STU2 = LW_STU.
WRITE: / LW_STU2-ID.
WRITE: / LW_STU2-NAME.
结果:
内表
1.APPEND
使用 LIT_STU TYPE STANDARD TABLE OF LTY_W_STU.定义内表为LIT_STU
后续增加LW_STU,LW_STU2到内表中,然后 CL_DEMO_OUTPUT=>DISPLAY( LIT_STU ).输出
下面有内表1添加到内表2的方法 APPEND LINES OF LIT_STU TO LIT_STU2.
也有添加新数据的注意事项Clear
TYPES:
BEGIN OF LTY_W_STU,
ID TYPE N LENGTH 4,
NAME TYPE C LENGTH 10,
AGE TYPE I,
SR TYPE I,
SCHID TYPE N LENGTH 4,
END OF LTY_W_STU.
DATA:
LW_STU TYPE LTY_W_STU,
LIT_STU TYPE STANDARD TABLE OF LTY_W_STU,
LIT_STU2 TYPE STANDARD TABLE OF LTY_W_STU.
LW_STU-ID = 2220.
LW_STU-NAME = 'Peter'.
LW_STU-AGE = 5.
LW_STU-SR = SY-DATUM.
LW_STU-SCHID = 0047.
WRITE: / LW_STU-ID.
WRITE: / LW_STU-NAME.
DATA:
LW_STU2 TYPE LTY_W_STU.
LW_STU2 = LW_STU.
LW_STU2-ID = 0002.
LW_STU2-NAME = 'Stu2'.
WRITE: / LW_STU2-ID.
WRITE: / LW_STU2-NAME.
APPEND LW_STU TO LIT_STU.
APPEND LW_STU2 TO LIT_STU.
"在追加数据之前,为了避免‘之前那的数据’对当前的数据造成影响
CLEAR LW_STU."清空一下当条数据
LW_STU-ID = 0003.
LW_STU-NAME = 'STU3'.
APPEND LW_STU TO LIT_STU.
APPEND LINES OF LIT_STU TO LIT_STU2."将结构相同的内表LIT_STU中的数据追加多条数据到LIT_STU2
CL_DEMO_OUTPUT=>DISPLAY( LIT_STU2 ).
结果:
INSERT INTO
将指定数据插入到指定位置
"在追加数据之前,为了避免‘之前那的数据’对当前的数据造成影响
CLEAR LW_STU."清空一下当条数据
LW_STU-ID = 0003.
LW_STU-NAME = 'STU3'.
*APPEND LW_STU TO LIT_STU.
INSERT LW_STU INTO LIT_STU INDEX 2."插入到指定位置:第二行
APPEND LINES OF LIT_STU TO LIT_STU2."将结构相同的内表LIT_STU中的数据追加多条数据到LIT_STU2
CL_DEMO_OUTPUT=>DISPLAY( LIT_STU2 ).
结果:
READ
LW_STU-ID = 0003.
LW_STU-NAME = 'STU3'.
*APPEND LW_STU TO LIT_STU.
INSERT LW_STU INTO LIT_STU INDEX 2."插入到指定位置:第二行
*APPEND LINES OF LIT_STU TO LIT_STU2."将结构相同的内表LIT_STU中的数据追加多条数据到LIT_STU2
READ TABLE LIT_STU INTO LW_STU INDEX 1.
CL_DEMO_OUTPUT=>DISPLAY( LW_STU ).
结果:
但是,如果我将index变成5,之后
还是会输出,明明第五行没有数据,为什么还是会输出?
是因为
定义了初始值,第五行没有数据,我就没有获取到,所以直接输出原始值,这种情况下,需要提前Clear一下
LW_STU-ID = 0003.
LW_STU-NAME = 'STU3'.
*APPEND LW_STU TO LIT_STU.
*INSERT LW_STU INTO LIT_STU INDEX 2."插入到指定位置:第二行
*APPEND LINES OF LIT_STU TO LIT_STU2."将结构相同的内表LIT_STU中的数据追加多条数据到LIT_STU2
CLEAR LW_STU."读取之前清空一下
READ TABLE LIT_STU INTO LW_STU INDEX 5.
"SY-SUBRC操作是否成功
WRITE :/ SY-SUBRC.
CL_DEMO_OUTPUT=>DISPLAY( LW_STU ).
结果:SY-SUBRC为0代表成功的意思,除0以为的其他数字为不成功
还可以使用关键字查找,查找id为0003的数据或者以其他字段进行查询
READ TABLE LIT_STU INTO LW_sTU WITH KEY ID = 0003.
WRITE : / SY-SUBRC.
IF SY-SUBRC = 0.
CL_DEMO_OUTPUT=>DISPLAY( LW_STU ).
ELSE.
MESSAGE E000(ZITO4700).
ENDIF.
结果:
还使用二分查找提高查找效率,但是前提必须进行排序,还可以倒序来排序,也可以多关键字排序
只需要在后面添加想要的字段就行,例如我想id和age进行排序,就都写在语句中SORT LIT_STU BY ID AGE.,升序是ASCENDING,降序是DESCENDING。
例如SORT LIT_STU BY ID DESCENDING.就是ID降序排序
SORT LIT_STU BY ID."以id进行排序
READ TABLE LIT_STU INTO LW_STU WITH KEY ID = 0002 BINARY SEARCH."使用二分法查找
WRITE : / SY-SUBRC.
IF SY-SUBRC = 0.
CL_DEMO_OUTPUT=>DISPLAY( LW_STU ).
ELSE.
MESSAGE E000(ZITO4700).
ENDIF.
原始数据表:
查找结果:
循环LOOP
LOOP AT LIT_STU INTO LW_STU."将内表中的数据逐条放到工作区里/结构体里
WRITE: / LW_STU-NAME.
ENDLOOP.
结果:
删除delete
DELETE LIT_STU INDEX 2."删除第二条数据
结果:
同样可以删除年龄=10的数据
DELETE LIT_STU WHERE AGE = 10.
删除初始值为空的数据使用INITIAL ,还有不为空的就是IS NOT INITIAL.
*DELETE LIT_STU INDEX 2."删除第二条数据
*DELETE LIT_STU WHERE AGE = 10."删除AGE=10的数据
DELETE LIT_STU WHERE SR IS INITIAL."删除SR为空/初始值的数据
删除重复数据
"去除重复数据
SORT LIT_STU BY ID.
DELETE ADJACENT DUPLICATES FROM LIT_STU COMPARING ALL FIELDS."对比所有的列,删除重复数据
清空内表:CLEAR,REFRESH,FREE
更新MODIFY
ABAP不允许直接对内表直接操作,所以如果想更改AGE,需要先对LW_STU进行操作,再通过LW_STU更新到表中,但是这是将0002号的所有字段都更新了
结果:
如果只想更新AGE可以增加TRANSPORTING