一、内表有关概念
1、内表的定义
在 ABAP 中,内表(Internal Table)是用于在内存中存储数据的结构,类似于数据库中的表,但它是在程序执行期间临时存在的。内表常用于在 ABAP 程序中处理和操作数据,比如将数据库查询结果存储在内表中,或者用于对数据进行各种操作,如排序、过滤、更新等。
内表是 ABAP 中最重要的数据结构之一,几乎所有与数据处理相关的操作都涉及到内表。
2、内表的类型及定义方法
a、标准内表(standard tables)
最常用的内表类型,它允许动态增长和删除行,但行的顺序并不是固定的。
DATA: 内表名称 TYPE (STANDARD) TABLE OF 类型(可以数据库表作为类型,这里填写表名).
b、排序内表(sorted tables)默认为升序排列。
排序内表在插入数据时会自动排序,它适用于查找操作,特别是当你需要按某种顺序访问数据时,排序内表比标准内表的性能更好。
DATA: 内表名称 TYPE SORTED TABLE OF 类型(可以数据库表作为类型,这里填写表名)
WITH UNIQUE KEY 列名(作为排序依据) .
c、哈希内表(hashed tables)
哈希内表通过哈希算法快速访问数据,特别适用于需要通过键来快速查找的场景。
DATA: 内表名称 TYPE HASHED TABLE OF 类型(可以数据库表作为类型,这里填写表名)
WITH UNIQUE KEY 列名(作为排序依据) .
二、插入数据
1、APPEND 向内表末尾插入一条数据。
本节以及后续演示所用到的内表定义以及结构体定义如下:
TYPES : BEGIN OF ty_student,
id TYPE i,
name TYPE string,
age TYPE i,
END OF ty_student.
DATA : lt_students TYPE STANDARD TABLE OF ty_student,
lv_student TYPE ty_student.
最初没有数据。
使用APPEND向内表末尾插入数据。插入两条数据,显示结果。
lv_student-id = 1.
lv_student-name = 'Via'.
lv_student-age = 22.
APPEND lv_student TO lt_students."追加至内表,至末尾
lv_student-id = 2.
lv_student-name = 'Libra'.
lv_student-age = 23.
APPEND lv_student TO lt_students.
WRITE: / ' 索引'.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
结果显示如下,APPEND追加至内表末尾。
2、INSERT 向指定位置插入一条数据。
INSERT 数据名(多用结构体) INTO 内表名 INDEX 行号.
lv_student-id = 1.
lv_student-name = 'Via'.
lv_student-age = 22.
APPEND lv_student TO lt_students."追加至内表,至末尾
lv_student-id = 2.
lv_student-name = 'Libra'.
lv_student-age = 23.
APPEND lv_student TO lt_students.
lv_student-id = 3.
lv_student-name = 'Soobin'.
lv_student-age = 24.
APPEND lv_student TO lt_students.
***********insert***********
lv_student-id = 4.
lv_student-name = 'Lily'.
lv_student-age = 25.
INSERT lv_student INTO lt_students INDEX 2."插入到第二位
***********insert***********
WRITE: / ' 索引'.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
可以从结果输出看到通过INSERT插入时,Lily变成了第二位,这里INDEX n会使成为第n个行。
3、COLLECT 插入同时对内表中的重复记录进行汇总。
COLLECT主要作用是根据指定的字段进行 分组,如果在内表中已经存在与当前行的非数值字段相同的记录,COLLECT会将该记录的数值字段累加到现有记录中;如果没有找到相同的记录,COLLECT会将该记录插入到内表中。(有记录则累加,没记录则插入)
运行下面这段代码。
*COLLECT根据非数值字段进行比较,将数值字段进行累加*
TYPES : BEGIN OF ty_class,
students TYPE i,
teacher TYPE i,
name TYPE string,
END OF ty_class.
DATA : lt_classes TYPE STANDARD TABLE OF ty_class,
lv_class TYPE ty_class.
lv_class-students = 20.
lv_class-teacher = 3.
lv_class-name = '一班'.
COLLECT lv_class into lt_classes.
lv_class-students = 45.
lv_class-teacher = 5.
lv_class-name = '二班'.
COLLECT lv_class into lt_classes.
lv_class-students = 30.
lv_class-teacher = 3.
lv_class-name = '一班'.
COLLECT lv_class into lt_classes.
cl_demo_output=>display( lt_classes ).
结果如下,发现结果中将两次一班的人数进行了累加。根据非数值字段name对students和teacher字段进行了累加。
三、删除数据
演示用学生内表初始数据如下(每次运行前数据都是该初始数据):
1、DELETE根据条件删除内表中记录。
a、根据索引删除数据。
DELETE 内表名 INDEX n.
ULINE.
WRITE : '删除索引为1的数据'.SKIP.
DELETE lt_students INDEX 1.
WRITE: / ' 索引'.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
运行后结果:
b、 根据条件删除。
DELETE 内表名 WHERE 条件.
1)如果只有一行符合条件。
ULINE.
WRITE : '删除名为Soobin的数据'.SKIP.
DELETE lt_students WHERE name = 'Soobin'.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
运行后结果:
2)如果有多行符合条件。
ULINE.
WRITE : '删除名为VIA的数据'.SKIP.
DELETE lt_students WHERE name = 'Via'.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
运行后结果如下,可以看到删除了所有名为Via的数据。
2、DELETE ADJACENT DUPLICATES删除相邻的重复项。
DELETE ADJACENT DUPLICATES FROM 内表名 (COMPARING 字段1 字段2 字段3).
区别于DELETE会删除所有符合条件的数据,DELETE ADJACENT DUPLICATES只会删除相邻的重复项,且会保留第一行。通过下面两个例子进行比较。
a、 删除name相同的字段。
ULINE.
WRITE : '删除全字段重复的数据'.SKIP.
DELETE ADJACENT DUPLICATES FROM lt_students COMPARING name.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
运行后结果如下,可以看到第一个Via由于和后两个Via不相邻,并没有被删除,后面的两个Via由于相邻被删除了,但是保留了相邻的索引靠前的那一个(注意她们的id)。DELETE ADJACENT DUPLICATES只会删除相邻的重复项,且会保留第一行。
那么如果我想将删除所有的重复项且保留一个要怎么做?
b、排序后删除name相同的字段。
ULINE.
SORT lt_students."根据全字段排序
WRITE : '排序后数据'.SKIP.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
ULINE.
WRITE : '删除全字段重复的数据'.SKIP.
DELETE ADJACENT DUPLICATES FROM lt_students.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
运行结果如下, 可以看到删除了id为5、6的Via,保留了id为1的Via。
c、 DELETE ADJACENT DUPLICATES总结。
DELETE ADJACENT DUPLICATES 只会删除相邻的重复项,且会保留重复项中的第一行。
所以在删除重复的数据之前 必须先对内表进行排序,具体如下:
1)若需要删除全字段匹配的数据 则直接sort+表名。
2)若需要删除某些字段相同的数据 则sort + 表名 + BY 字段名1 字段名2 字段名3。
3)删除语句:DELETE ADJACENT DUPLICATES FROM 表名 COMPARING 字段名1 字段名2 字段名3。(ALL FIELDS-全部字段)
3、CLEAR清空内表中数据。
CLEAR 表名.
ULINE.
CLEAR lt_students.
WRITE : 'CLEAR后的数据'.SKIP.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
四、修改数据
READ TABLE 内表名 INTO 结构体 WITH TABLE KEY 条件.
MODIFY TABLE 内表名 FROM 结构体.
*修改内表中数据*
READ TABLE lt_students INTO lv_student WITH TABLE KEY name = 'Via'."with table key只会返回第一条符合条件的数据
lv_student-id = 888.
MODIFY TABLE lt_students FROM lv_student."根据结构体来修改内表数据
ULINE.
WRITE : '修改后数据'.
LOOP AT lt_students INTO lv_student.
WRITE: / sy-tabix, lv_student-id, lv_student-name.
ENDLOOP.
可以看到,虽然条件WITH TABLE KEY name='Via'有三个满足条件的学生,但是READ的结果只会返回第一个结果。
修改数据的具体步骤:
a、READ找到需要修改的数据。
b、MODIFY对内表进行修改。
注:MODIFY在数据库里面没有符合条件的数据的时候会增加数据。
五、查询数据
1、根据索引进行查询。
READ TABLE 内表名 INTO 结构体 INDEX n.
READ TABLE lt_students INTO lv_student INDEX 1."读取索引为1的那个行
WRITE : / '索引为1的学生是',lv_student-id,lv_student-name,lv_student-age.
查询结果:
2、根据关键字查询。
READ TABLE 内表名 INTO 结构体 WITH KEY 条件.
READ TABLE lt_students INTO lv_student WITH KEY name = 'Libra'.
WRITE : / '关键字NAME是Libra的人是',lv_student-id,lv_student-name,lv_student-age.
查询结果:
3、二分法查询。
a、给表排序:SORT 表名 BY 字段名 (ASCENDING)/DESCENDING.(默认升序可以不写,降序写 DESCENDING)
b、二分法查找:READ TABLE 内表名 INTO 结构体 WITH KEY 条件 BINARY SEARCH。
SORT lt_students BY name ASCENDING.
READ TABLE lt_students INTO lv_student WITH KEY name = 'Soobin' BINARY SEARCH.
WRITE : / '二分法查找关键字NAME是Soobin的人是',lv_student-id,lv_student-name,lv_student-age.
查询结果:
数据量更大的时候才会体现处二分法的作用。 二分法思想
4、LOOP循环查询。
LOOP AT 内表名 INTO 结构体 (WHERE 条件).
SORT lt_students BY id ASCENDING.
WRITE : '排序后,根据条件name = Via 循环读取:'.SKIP.
WRITE: / ' 索引'.
LOOP AT lt_students INTO lv_student WHERE name = 'Via'.
WRITE: / sy-tabix, lv_student-id, lv_student-name,lv_student-age.
ENDLOOP.
条件查询的时候,只会查询出满足条件的行。