内表是每个ABAP开发人员都必须懂的,数据从R3取出来后,就是放在内表里处理的,其实就是Java中的集合框架,只是没有那么多不同数据结构的内表,目前只有标准、排序、Hash三种,这还是新的语法,老的只有个标准的,关于内表这方面的定义、性能,以后我专贴一篇文章吧。这里只是对内表的常用操作,这也是项目中用得最多的点!

3. 内表 ... 33

3.1. LOOP AT 循环内表 ... 33

3.1.1. SUM .. 34

3.1.2. AT... ENDAT . 34

3.1.3. 自已实现 AT... ENDAT . 37

3.2. LOOP AT 中修改当前内表行 ... 39

3.2.1. 循环中修改索引表 ... 39

3.2.2. 循环中修改 HASH ... 40

3.3. 第二索引 ... 40

3.3.1. 使用第二索引 ... 41

3.3.2. 示例 ... 41

3.4. 适合所有类型的内表操作 ... 42

3.5. 适合索引内表操作 ... 43

3. 内表

3.4. 适合所有类型的内表操作

COLLECT [<wa> INTO ] < itab > 将具有相同关键字段值的行中同名的数字字段的值累计到一条记录上 只有非表关键字段被累加 当在内表中找不到指定的被累加行时 COLLECT 语句的功能与 APPEND 语句是一样的 即将一个工作区的内容附加到 itab 内表中。使用 COLLECT 操作的内表有一个限制,即该的行结构中, 除了表键字段以外的所有字段都必须是数字型( i p f

INSERT <wa> INTO TABLE <itab>. " 单条插入

INSERT LINES OF <itab1> [ FROM <n1>] [ TO <n2>] INTO TABLE <itab2> " 批量插入

UNIQUE 的排序表或哈希表插入 重复的数据 不会抛异常 但数据 不会被插入进去 这与 APPEND 是不一样的

" 只要根据关键字或索引在内表中读取到相应数据,不管该数据行是否与 COMPARING 指定的字段相符,都会存储到工作区

READ TABLE <itab> WITH KEY {<k1> = <f1> ... <kn> = <fn>... [ BINARY SEARCH ] }

INTO <wa> [ COMPARING <f1><f2> ...|ALL FIELDS]

[ TRANSPORTING <f1><f2> ...|ALL FIELDS| NO FIELDS ]

| ASSIGNING <fs>

READ TABLE <itab> FROM <wa>… 以表关键字为查找条件 条件值来自 <wa>

COMPARING 系统根据 <k1>...<kn> 关键字段 读取指定的单行与工作区 <wa> 中的相应组件进行比较。

如果系统找根据指定 <k1>...<kn> 找到了对应的条目,且进行比较的字段内容相同,则将 SY-SUBRC 设置为 0 ,如果进行比较的字段内容不同,则返回值 2 ;如果系统根据 <k1>...<kn> 找不到条目,则包含 4 。如果系统找到条目,则无论比较结果如何,都将其读入 wa

MODIFY TABLE <itab> FROM <wa> [ TRANSPORTING <f1> <f2> ...] " 修改单条 MODIFY TABLE < itab > 一般用在循环中 修改哈希表 ,且 itab 内表带表头) 。这里的 <wa> 扮演双重身份,不仅指定了要修改的行(条件),还包括要修改的新的值。系统以整个表的所有关键字段来搜索要修改的行; USING KEY :如果未使用此选项,则会使用默认的主键 primary table key 来修改相应的行;如果找到要修改的行,则将 <wa> 中所有非关键字段的内容拷贝到对应的数据行中对应的字段上;如果有多行满足条件时只修改第一条

MODIFY <itab> FROM <wa> TRANSPORTING<f1><f2>... WHERE <cond> " 修改多条

DELETE TABLE <itab> FROM <wa> " 删除单条 。多条时,只会删除第一条。条件为所有表关键字段,值来自 <wa>

DELETE TABLE <itab> WITH TABLE KEY <k1> = <f1> ... " 删除单条 。多条时只会删除第一条 , 条件为所有表关键字

DELETE itab WHERE ( col2 > 1 ) AND ( col1 < 4 ) " 删除多行

DELETE ADJACENT DUPLICATES FROM <itab> [ COMPARING <f1><f2> ... | ALL FIELDS ]

注,在未使用 COMPARING 选项时,要删除重复数据之前, 一定要按照内表关键字声明的顺序来进行排序,才能删除重复数据 ,否则不会删除掉;如果指定了 COMPARING 选项,则需要根据指定的比较字段顺序进行排序(如 COMPARING <F1><F2> 时,则需要 sort by <F1><F2> ,而不能是 sort by <F2><F1> ),才能删除所有重复数据

3.5. 适合索引内表操作

APPEND <wa> TO <itab>

APPEND LINES OF <itab1> [ FROM <n1>] [ TO <n2>] TO <itab2>

INSERT <wa> INTO <itab> INDEX <idx> " 如果不使用 INDEX 选项,则将新的行插入到当前行的前面,一般在 Loop 中可省略 INDEX 选项

INSERT LINES OF <itab1> [ FROM <n1>] [ TO <n2>] INTO <itab2> INDEX <idx>

APPEND/INSERT …INDEX 操作不能用于 Hash

APPEND/INSERT…INDEX 用于排序表时条件:附加 / 插入时一定要按照 Key 的升序来附加;如果是 Unique 排序表, 则不能附加 / 插入重附的数据 ,这与 INSERT…INTO TABLE 是不一样的

READ TABLE <itab> INDEX <idx>

INTO <wa> [ COMPARING <f1><f2> ...|ALL FIELDS]

[ TRANSPORTING <f1><f2> ...|ALL FIELDS| NO FIELDS ]

| ASSIGNING <fs>

MODIFY <itab> [ INDEX <idx> ] FROM <wa> [ TRANSPORTING <f1> <f2> ... ] " 如果没有 INDEX 选项,只能在 循环中使用该语句

DELETE <itab> [ INDEX <idx>] " 删除单条 。如果省略 <index> 选项,则 DELETE <itab> 语句只能用在循环语句中

DELETE <itab> [ FROM <n1>] [ TO <n2>] WHERE <condition> " 删除多条

3.1. LOOP AT 循环内表

LOOP AT itab { INTO wa} | { ASSIGNING <fs> [ CASTING ]} | { TRANSPORTING NO FILDS }
[ [
USING KEY key_name| ( name ) ] [ FROM idx1] [ TO idx2] [ WHERE log_exp| ( cond_syntax ) ] ]
.

ENDLOOP .

FROM … TO: 只适用于标准表与排序表 WHERE …  : 适用于所有类型的内表

如果没有通过 USING KEY 选项的 key_name 则循环读取的顺序与表的类型相关

l 标准表与排序表 会按照 primary table index 索引的顺序一条条的循环 且在循环里 SY-TABIX 为当前正在处理行的索引号

l 哈希表 由于表没有排序 所以 按照插入的顺序来循环处理 ,注,此时 SY-TABIX 总是 0

可以在循环内表时增加与删除当前行 If you insert or delete lines in the statement block of a LOOP , this will have the following effects:

  • If you insert lines behind (后面) the current line, these new lines will be processed in the subsequent loop (新行会在下一次循环时被处理) passes. An endless loop (可能会引起死循环) can result
  • If you delete lines behind the current line, the deleted lines will no longer be processed in the subsequent loop passes
  • If you insert lines in front (前面) of the current line, the internal loop counter is increased by one with each inserted line. This affects sy-tabix in the subsequent loop pass( 这会影响在随后的循环过程 SY- TABIX )
  • If you delete lines in front of the current line, the internal loop counter is decreased by one with each deleted line. This affects sy-tabix in the subsequent loop pass
  • 3.1.1. SUM

    如果在 AT - ENDAT 块中使用 SUM 则系统计算当前行组中 所有 行的数字字段之和并将其写入工作区域中相应的字段中

    3.1.2. AT... ENDAT

    在使用 AT...... ENDAT 之前, 一这要先按照这些语句中的组件名进行排序,且排序的顺序要与在 AT...... ENDAT 语句中使用顺序一致 ,排序与声明的顺序决定了先按哪个分组,接着再按哪个进行分组,最后再按哪个进行分组,这与 SQL 中的 Group By 相似

    用在 AT...... ENDAT 语句中的中的组件名不一定要是结构中的关键字段 ,但这些字段一定要按照出现在 AT 关键字后面的使用顺序在结构最前面进行声明,且 这些组件字段的声明之间不能插入其他组件的声明 如现在需要按照 <f1>, <f2>, .... 多个字段的顺序来使用在 AT...... ENDAT 语句中,则首先需要在结构中按照 < f1>, <f2>, ...., 多字段的顺序在结构最前面都声明,然后按照 <f1>, <f2>, ...., 多字段来排序的,最后在循环中按如下的顺序块书写程序(请注意书写 AT END OF 的顺序与 AT NEW 是相反 的,像下面这样):

    LOOP AT <itab>.

    AT FIRST. ... ENDAT.

    AT NEW <f1>. ...... ENDAT.

    AT NEW <f 2 >. ...... ENDAT.

    .......

    <single line processing>

    .......

    AT END OF <f2>. ... ENDAT.

    AT END OF <f1>. ... ENDAT.

    AT LAST. .... ENDAT.

    ENDLOOP.

    一旦进入到 AT...<f1>...ENDAT 块中时,当前工作区(或表头)中的从 <f1> 往后 ,但不包括 <f1> (按照在结构中声明的次序)所有字段的字符类型字段会以星号 (*) 号来填充,而数字字设置为初始值(注:在测试过程中发现 String 类型不会使用 * 来填充,而是设置成 empty String ,所以只有固定长度类型的非数字基本类型才设置为 * )。如果在 AT 块中使用了 SUM ,则会将所有数字类型字段统计出来将存入当前工作区(或表头);但一旦离开 AT....ENDAT 块后,又会将当前遍历的行恢复到工作区(或表头)中

    DATA : BEGIN OF th_mseg OCCURS 10 ,
    matnr
    TYPE mard-matnr, werks TYPE mard-werks,
    lgort
    TYPE mard-lgort, shkzg TYPE mseg-shkzg,
    menge
    TYPE mseg-menge, budat TYPE
    mkpf-budat,
    LOOP AT
    th_mseg.
    AT END OF shkzg . "
    会根据 shkzg 及前面所有字段来进行分组
    sum .
    WRITE
    : / th_mseg-matnr, th_mseg-werks,th_mseg-lgort,
    th_mseg-shkzg,th_mseg-menge,th_mseg-budat.
    ENDAT
    .
    ENDLOOP
    .

    AS-101             2300 0001 S           10.000  ****.**.**

    AS-100             2300 0002 S           10.000  ****.**.**

    AS-100             2300 0001 S           20.000  ****.**.**

    上面由于没有根据 matnr + werks + lgort + shkzg 进行排序,所以结果中的第三行其实应该与第一行合并。 其实这个统计与 SQL 里的分组( Group By )统计原理是一样的, Group By 后面需要明确指定分组的字段,如上面程序使用 SQL 分组写法应该为 Group By matnr werks lgort shkzg ,但在 ABAP 里你只需要按照 matnr werks lgort shkzg 按照先后顺序在结构定义的最前面进行声明就可表达了 Group By 那种意义,而且不一定要将 matnr werks lgort shkzg 这四个字段全部用在 AT 语句块中 AT NEW AT END OF shkzg 才正确,其实像上面程序一样,只写 AT END OF shkzg 这一个语句,前面三个字段 matnr werks lgort 都可以不用在 AT 语句中出现,因为 ABAP 默认会按照结构中声明的顺序将 shkzg 前面的字段也全都用在了分组中了

    DATA : BEGIN OF line ,
    " C2 C3 组件名声明的顺序一定要与在 AT...... ENDAT 块中使用的次序一致,即这里不能将 C3 声明在 C2 之前,且不能在 C2 C3 之间插入其他字段的声明
    c2
    ( 5 ) TYPE c ,
    c3
    ( 5 ) TYPE c ,
    c4
    ( 5 ) TYPE c ,
    i1
    TYPE i ,
    i2
    TYPE i ,
    c1
    ( 5 ) TYPE c ,
    END OF line .

    " 使用在 AT...... E NDAT 语句中的 字段不一定要是关键字段
    DATA : itab LIKE TABLE OF line WITH HEADER LINE WITH NON-UNIQUE KEY i1 .
    PERFORM append USING 2 'b' 'bb' 'bbb' '2222' 22 . PERFORM append USING 3 'c' 'aa' 'aaa' '3333' 33 .
    PERFORM append USING 4 'd' 'aa' 'bbb' '4444' 44 . PERFORM append USING 5 'e' 'bb' 'aaa' '5555' 55 .
    PERFORM append USING 6 'f' 'bb' 'bbb' '6666' 66 . PERFORM append USING 7 'g' 'aa' 'aaa' '7777' 77 .
    PERFORM append USING 8 'h' 'aa' 'bbb' '8888' 88
    .
    SORT itab ASCENDING BY c2 c3 .
    LOOP AT itab .
    WRITE : / itab - c2 , itab - c3 , itab - c1 , itab - c4 , itab - i1 , itab - i2 .
    ENDLOOP .
    SKIP .
    LOOP AT itab .

    AT FIRST .
    WRITE : / '>>>> AT FIRST' .
    ENDAT .
    AT NEW c2 .
    WRITE : / '    >>>> Start of' , itab - c2 .
    ENDAT .
    AT NEW c3 .
    WRITE : / '        >>>> Start of' , itab - c2 , itab - c3 .
    ENDAT .
    " 只要一出 AT 块,则表头的数据又会恢复成当前被遍历行的内容
    WRITE : / itab - c2 , itab - c3 , itab - c1 , itab - c4 , itab - i1 , itab - i2 .
    AT END OF c3 .
    SUM .
    WRITE : / itab - c2 , itab - c3 , itab - c1 , itab - c4 , itab - i1 , itab - i2 .
    WRITE : / '        <<<< End of' , itab - c2 , itab - c3 .
    ENDAT .
    AT END OF c2 .
    SUM .
    WRITE : / itab - c2 , itab - c3 , itab - c1 , itab - c4 , itab - i1 , itab - i2 .
    WRITE : / '    <<<< End of' , itab - c2 .
    ENDAT .

    AT LAST .
    SUM .
    WRITE : / itab - c2 , itab - c3 , itab - c1 , itab - c4 , itab - i1 , itab - i2 .
    WRITE : / '<<<< AT LAST' .
    ENDAT .
    ENDLOOP .
    TYPES : c5 ( 5 ) TYPE c .
    FORM append  USING    value ( p_i1 ) TYPE I value ( p_c1 ) TYPE c5 value ( p_c2 ) TYPE c5
    value ( p_c3 ) TYPE c5 value ( p_c4 ) TYPE c5 value ( p_i2 ) TYPE i .

    itab
    - i1 = p_i1 . itab - c1 = p_c1 . itab - c2 = p_c2 .
    itab
    - c3 = p_c3 . itab - c4 = p_c4 . itab - i2 = p_i2 .
    APPEND itab .
    ENDFORM .

    aa    aaa   c     3333           3          33

    aa    aaa   g     7777           7          77

    aa    bbb   d     4444           4          44

    aa    bbb   h     8888           8          88

    bb    aaa   a     1111           1          11

    bb    aaa   e     5555           5          55

    bb    bbb   b     2222           2          22

    bb    bbb   f     6666           6          66

    >>>> AT FIRST

    >>>> Start of aa

    >>>> Start of aa    aaa

    aa    aaa   c     3333           3          33

    aa    aaa   g     7777           7          77

    aa    aaa   ***** *****          10         110

    <<<< End of aa    aaa

    >>>> Start of aa    bbb

    aa    bbb   d     4444           4          44

    aa    bbb   h     8888           8          88

    aa    bbb   ***** *****          12         132

    <<<< End of aa    bbb

    aa    ***** ***** *****           22         242

    <<<< End of aa

    >>>> Start of bb

    >>>> Start of bb    aaa

    bb    aaa   a     1111           1          11

    bb    aaa   e     5555           5          55

    bb    aaa   ***** *****           6          66

    <<<< End of bb    aaa

    >>>> Start of bb    bbb

    bb    bbb   b     2222           2          22

    bb    bbb   f     6666            6          66

    bb    bbb   ***** *****           8          88

    <<<< End of bb    bbb

    bb    ***** ***** *****           14         154

    <<<< End of bb

    ***** ***** ***** *****            36         396

    <<<< AT LAST

    3.1.3. 自已实现 AT... ENDAT

    如果循环的内表不是自己定义的 有时无法将分组的字段按顺序声明在一起 所以需要自己实现这些功能 下面是自己实现 AT NEW AT END OF 另一好处是在循环内表时 可以使用 Where 条件语句 )( 使用这种只需要按照分组的顺序排序即可 如要分成 bukrs bukrs anlkl 两组时 需要按照 BY bukrs anlkl 排序 而不能是 BYanlkl bukrs ):

    DATA : lp_bukrs TYPE bukrs , " 上一行 bukrs 字段的值
    lp_anlkl
    TYPE anlkl . " 上一行 anlkl
    字段的值

    " 下面假设按 bukrs bukrs anlkl 分成两组
    SORT itab_data BY bukrs
    anlkl.
    DATA : i_indx TYPE i
    .

    DATA : lwa_data Like itab_data
    LOOP AT itab_data where flg = 'X '
    .

    i_indx = sy - tabix.
    " **********AT NEW 对当前分组首行进行处理

    IF itab_data - bukrs <> lp_bukrs . "Bukrs
    ".........
    ENDIF .
    IF itab_data - bukrs <> lp_bukrs OR itab_data - anlkl <> lp_anlkl . "bukrs anlkl 分组
    ".........
    ENDIF .
    IF itab_data - bukrs <> lp_bukrs OR itab_data - anlkl <> lp_anlkl OR itab_data - . . <> lp_ . . . "bukrs anlkl .. 分组
    ".........
    ENDIF .


    "********** 普通循环处理
    ".........

    "**********AT END OF 对当前分组末行进行处理

    DATA : l_nolast1 , l_nolast12 . " 不是分组中最末行

    " 这里还是要清一下,以防该代码直接写在报表程序的事件里,而不是 Form 里(直接放在 Report 程序事件里时, l_nolast1,l_nolast12 将会成为全局变量)
    CLEAR:  l_nolast1,l_nolast12,l_nolast...
    DO .
    i_indx
    = i_indx  + 1 .
    READ TABLE itab_data INTO lwa_data INDEX i_indx . " 尝试读取下一行
    IF sy - subrc <> 0 . " 当前行已是内表中最后一行
    EXIT .
    " 如果第一分组字段都发生了变化,则意味着当前行为所有分组中的最后行
    " 注:即使有 N 个分组,这里也只需要判断第一分组字段是否发生变化,不
    " 需要对其他分组进行判断,即这里不需要添加其他 ELSEIF 分支
    ELSEIF lwa_data - bukrs <> itab_data - bukrs .
    EXIT .
    ENDIF .
    ********
    断定满足条件的下一行不是分组最的一行
    " 如果 Loop 循环中没有 Where 条件,则可以将下面条件 lwa_data-flg = 'X' 删除即可
    IF sy - subrc = 0 AND lwa_data - flg = 'X' .
    IF lwa_data - bukrs = itab_data - bukrs . " 判断当前行是否是 bukrs 分组最后行
    l_nolast1
    = '1' .
    IF lwa_data - nanlkl = itab_data - nanlkl . " 判断当前行是否是 bukrs nanlkl 分组最后行
    l_nolast2
    = '1' .
    IF lwa_data - . . = itab_data - . . . " 判断当前行是否是 bukrs nanlkl .. 分组最后行
    l_nolast
    . . = '1' .
    ENDIF .
    ENDIF .
    EXIT . " 只要进到此句所在外层 If ,表示找到了一条满 Where 条件的下一行数据,因此,只要找到这样的数据就可以判断当前分组是否已完,即一旦找到这样的数据就不用再往后面找了,则退出以防继续往下找
    ENDIF .
    ENDIF .

    ENDDO .

    IF l_nolast . . IS INITIAL " 处理 bukrs nanlkl .. 分组
    . . . . .
    .
    ENDIF
    .

    IF l_nolast2 IS INITIAL . " 处理 bukrs nanlkl 分组
    . . . . . .
    ENDIF .

    IF l_nolast1 IS INITIAL . " 处理 bukrs 分组
    . . . . .
    .
    ENDIF
    .


    lp_bukrs = itab_data - bukrs .
    lp_anlkl
    = itab_data - anlkl .

    lp_.. = itab_data - .. .
    ENDLOOP .

    3.2. LOOP AT 中修改当前内表行

    3.2.1. 循环中修改 索引表

    TYPES : BEGIN OF line ,
    key
    ,
    val
    TYPE i ,
    END OF line .
    DATA : itab1 TYPE line OCCURS 0 WITH HEADER LINE .
    DATA : itab2 TYPE line OCCURS 0 WITH HEADER LINE .
    itab1
    - key = 1 .
    itab1
    - val = 1 .
    APPEND itab1 .
    itab2
    = itab1 .
    APPEND itab2 .
    itab1
    - key = 2 .
    itab1
    - val = 2 .
    APPEND itab1 .
    itab2
    = itab1 .
    APPEND itab2 .

    LOOP AT itab1 .
    WRITE : / 'itab1 index: ' , sy - tabix .
    READ TABLE itab2 INDEX 1 TRANSPORTING NO FIELDS . " 试着读取其他内表
    "READ TABLE itab1 INDEX 1 TRANSPORTING NO FIELDS." 读取本身也不会影响后面的 MODIFY 语句
    WRITE : / 'itab2 index: ' , sy - tabix .
    itab1
    - val = itab1 - val + 1 .
    " 在循环中可以使用下面简洁方法来修改内表,修改的内表行为当前正被循环的行,即使循环中使用了
    "READ TABLE 语句读取了其他内表 ( 读取本身也没有关系 ) 而导致了 sy-tabix 发生了改变 ,因为以下
    " 语句不是根据 sy-tabix 来修改的 ( 如果在前面读取内表导致 sy-tabix
    发生了改变发生改变后,再使用

    " MODIFY itab1 INDEX sy-tabix 语句进行修改时,反而不正确。 而且该语句还适用于 Hash 内表, 需在
    "MODIFY
    后面加上 TABLE 关键字后再适用于 Hash ——请参见后面章节示例
    )

    MODIFY itab1 .
    ENDLOOP .
    LOOP AT itab1 .
    WRITE : / itab1 - key , itab1 - val .
    ENDLOOP .

    3.2.2. 循环中修改 HASH

    TYPES : BEGIN OF line ,
    key
    ,
    val
    TYPE i ,
    END OF line .
    DATA : itab1 TYPE HASHED TABLE OF line WITH HEADER LINE  WITH UNIQUE KEY key .
    DATA : itab2 TYPE line OCCURS 0 WITH HEADER LINE .
    itab1
    - key = 1 .
    itab1
    - val = 1 .
    INSERT itab1 INTO TABLE itab1 .
    itab2
    = itab1 .
    APPEND itab2 .
    itab1
    - key = 2 .
    itab1
    - val = 2 .
    INSERT itab1 INTO TABLE itab1 .
    itab2
    = itab1 .
    APPEND itab2 .

    LOOP AT itab1 .
    WRITE : / 'itab1 index: ' , sy - tabix . " 循环哈希表时 sy-tabix 永远是 0
    READ TABLE itab2 INDEX 1 TRANSPORTING NO FIELDS .
    WRITE : / 'itab2 index: ' , sy - tabix .
    itab1
    - val = itab1 - val + 1 .
    MODIFY TABLE itab1 . " 该语句不一定在要放在循环里才能使用 —— 循环外修改 Hash 也是一样的 这与上面的索引表循环修改是不一样的 并且修改的条件就是 itab1 表头工作区, itab1 即是条件,也是待修改的值,修改时会 根据内表设置的主键来修改,而不是索引号

    ENDLOOP .
    LOOP AT itab1 .
    WRITE : / itab1 - key , itab1 - val .
    ENDLOOP .

    3.3. 第二索引

    三种类型第二索引:

    2 UNIQUE  HASHED 哈希算法第二索引

    2 UNIQUE  SORTED 唯一升序第二索引

    2 NON-UNIQUE  SORTED 非唯一升序第二索引

    TYPES sbook_tab TYPE STANDARD TABLE OF sbook
    "
    主索引 如果要为主索引指定名称 则只能使用预置的 primary_key 但可以通过后面的 ALIAS 选项来修改 ALIAS 选项只能用于排序与哈希表
    WITH NON-UNIQUE KEY primary_key "ALIAS my_primary_key
    COMPONENTS carrid connid fldate bookid
    "
    第一个第二索引 唯一哈希算法
    WITH UNIQUE HASHED KEY hash_key
    COMPONENTS
    carrid connid
    "
    第二第二索引 唯一升序排序索引
    WITH UNIQUE SORTED KEY sort_key1
    COMPONENTS
    carrid bookid
    "
    第三第二索引 非唯一升序排序索引
    WITH NON-UNIQUE SORTED KEY sort_key2
    COMPONENTS customid
    .

    3.3.1. 使用第二索引

    1、 可以在 READ TABLE itab MODIFY itab DELETE itab LOOP AT itab 内表操作语句中通过 WITH [TABLE] KEY key_name COMPONENTS K 1 = V 1 ... 或者 USING KEY key_name ,语句中的 key_name 为第二索引名:

    READ TABLE itab WITH TABLE KEY [ key_name COMPONENTS ] {K 1 | ( K 1 ) } = V 1 ... INTO wa

    READ TABLE itab WITH KEY key_name COMPONENTS {K 1 | ( K 1 ) } = V 1 ... INTO wa

    READ TABLE itab FROM wa [ USING KEY key_name] INTO wa

    READ TABLE itab INDEX idx [ USING KEY key_name] INTO wa

    MODIFY TABLE itab [ USING KEY key_name] FROM wa

    MODIFY itab [ USING KEY loop_key] FROM wa 此语句只能用在 LOOP AT 内表循环 语句中,并且此时 USING KEY loop_key 选项也可以省略(其实默认就是省略的),其中 loop_key 是预定义的,不能写成其他名称

    MODIFY itab INDEX idx [ USING KEY key_name] FROM wa

    MODIFY itab FROM wa [ USING KEY key_name] ... WHERE ...

    DELETE TABLE itab FROM wa [ USING KEY key_name]

    DELETE TABLE itab WITH TABLE KEY [ key_name COMPONENTS ] {K 1 | ( K 1 ) } = V 1 ...

    DELETE itab INDEX idx [ USING KEY key_name| ( name ) ]

    DELETE itab [ USING KEY loop_key]

    DELETE itab [ USING KEY key_name ] ... WHERE ...

    DELETE ADJACENT DUPLICATES FROM itab [ USING KEY key_name] [ COMPARING K1 K2 ...]

    LOOP AT itab USING KEY key_name WHERE ... .
    ENDLOOP .

    2、 可以在 INSERT itab APPEND 语句中通过 USING KEY 选项来使用第二索引

    INSERT wa [ USING KEY key_name] INTO TABLE itab

    APPEND wa [ USING KEY key_name] TO itab

    3.3.2. 示例

    DATA itab TYPE HASHED TABLE OF dbtab WITH UNIQUE KEY col1 col2 ...
    " 向内表 itab 中添加大量的数据 ...
    READ TABLE itab " 使用 主键进行搜索,搜索速度将会很慢
    WITH KEY col3 = ... col4 = ...
    ASSIGNING ...
    上面定义了一个哈希内表,在读取时未使用主键,在大数据量的情况下速度会慢,所以在搜索字段上创建第二索引:
    DATA itab
    TYPE HASHED TABLE OF dbtab
    WITH UNIQUE KEY col1 col2 ...

    " 为非主键创建第二索引
    WITH NON-UNIQUE SORTED KEY second_key
    COMPONENTS col3 col4 ...

    " 向内表 itab 中添加大量的数据 ...
    READ TABLE itab " 根据第二索引进行搜索,会比上面程序快
    WITH TABLE KEY
    second_key
    COMPONENTS col3 = ... col4 = ...

    ASSIGNING ...
    " 在循环内表的 Where 条件中,如果内表不是排序内表,则不会使用二分搜索,如果使用 SORTED KEY ,则循环时, 会用到二分搜索?
    LOOP AT itab USING KEY second_key where col3 = ... col4 = ... .
    ENDLOOP .

    原文出自 江正军 技术博客,博客链接: www.cnblogs.com/jiangzhengjun