ABAP 内表 详解

时间:2021-02-21 20:29:48
ABAP 内表 详解
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4293475.html

内表

老式的内表类型定义

老式内表只有标准内表一种,使用OCCURS选项来定义了标准内表,这是ABAP3.0之前的定义内表的做法了,在新版的ABAP不建议使用,因为在新的版本中有三种内表类型(标准、排序、哈希)。

TYPES <t><type> OCCURS <n>.

内表中行的数据类型在<type>中指定。要指定行的数据类型,可以使用 TYPE 或 LIKE 参数。

基于基本类型内表类型

.
"如果要带隐藏表头则一定要加上WITH HEADER LINE,否则默认没有,而且只能在声明内表变量时加,而不能在上面定义内表类型时加
DATA vector TYPE vector WITH HEADER LINE.

vector = 1.
APPEND vector.

上面的TYPES与下面语句等效:

.

本示例创建内表数据类型 vector,其行包含基本类型 I 字段。

 

注:WITH HEADER LINE只能与DATA关键字一起使用,而不能与TYPES一起使用,这也就是说,只有在分配了存储空间时才有隐藏工作区这一说,在定义内表类型时是没有的。

下面这样也可以:

 .
APPEND vector.

基于结构体类型内表类型

.

本示例创建内表数据类型itab,其行与字段串line结构相同。

特别注意,上面代码不能简单的写成如下形式,否则编译出错:

,
         column1 TYPE i,
         column2 TYPE i,
         column3 TYPE i,
       END OF itab.

即使用TYPES关键字定义内表类型时,不允许直接在结构类型(在简单的类型后面又可以,如最上面的示例所示)后面加上 OCCURS 选项来将原来为结构类型转换成内表类型,需要像前面一样间接定义,但DATA关键字是可以的,这种语法规则非常特别。

老式的内表对象创建

参照现有内表类型或内表对象来创建

DATA <f><type> [WITH HEADER LINE].

注:<type>必须是已存在的内表数据类型或内表数据对象(内表类型时使用TYPE 、内表对象使用 LIKE)

.
DATA vector TYPE type WITH HEADER LINE.

参照现有结构类型或结构对象来创建

DATA <f><type> OCCURS <n> [WITH HEADER LINE].

注:<type>可以是已存在的结构类型或结构对象(结构类型时使用TYPE 、结构对象使用 LIKE),当然也可以不是结构类型,而是内表类型或基本类型都可以:

TYPES typeTYPE i.
DATA vector TYPE type OCCURS 0 WITH HEADER LINE.

两种内表对象等效创建

本示例介绍如何采用两种不同的步骤创建同一内表。

.
DATA vector TYPE vector_type WITH HEADER LINE.

通过直接在 DATA 语句中使用 OCCURS 选项创建与上面完全一样的数据类型 VECTOR:

WITH HEADER LINE."DATA vector TYPE i OCCURS 10表示vector是一个内表而不是类型I的变量

OCCURS的作用就是将普通类型转换为内表类型

l  要创建既不引用现有对象,也不引用现有行结构的内表数据对象

DATA: BEGIN OF <f> OCCURS <n>,
  <component declaration>,
  ...
end of <f>.

该语句会默认创建一个表头。相当于:

DATA itab TYPE STANDARD TABLE OF lineType
      WITH NON-UNIQUE DEFAULT KEY
      INITIAL SIZE n
      WITH HEADER LINE.

本示例会自动创建默认表格工作区域 ITAB:

,
         column1 TYPE i,
         column2 TYPE i,
         column3 TYPE i,
       END OF itab.

但下面这种方式不会自动创建隐式工作区,除非在OCCURS 10后面加上选项“WITH HEADER LINE”(使用DATA...LIKE/TYPE...OCCURS时不会创建默认工作区,只有DATA: BEGIN OF ... OCCURS ...才会):

."itab是一个内表而不是一个结构,与DATA itab LIKE standard table of line 等效

类似的还有语句:

TYPES tab TYPE|LIKE linetype OCCURS n.

DATA itab TYPE|LIKE linetype OCCURS n[WITH HEADER LINE].

相当于:

TYPES|DATA itab TYPE|LIKE STANDARD TABLE OF linetype
        WITH NON-UNIQUE DEFAULT KEY
        INITIAL SIZE n
[with header line]."该选项只适用于DATA关键字,不能与TYPES一起使用

上述两种形式均只适用于创建标准表,因为在旧的SAP版本中,标准表是唯一的内表类型。

带默认表头的内表的行类型不能是内表

如果想创建带表头行的内表,行类型不能直接是内表,但可以用内表作为组件的结构:

.
.

TYPES t3 TYPE t2.
"由于t2的行类型还是内表,所以会报错:with header lne 不能用于类型为内表类型时

*DATA d1 TYPE t3 WITH HEADER LINE.
*DATA d1 TYPE t2 WITH HEADER LINE.

"下面这种实质上与上面  DATA d1 TYPE t2 WITH HEADER LINE. 语句是一样效果,所以也会报错
*DATA d2 TYPE  t1  OCCURS 10  WITH HEADER LINE.

.
"与上面语句等效
*DATA d2 TYPE  t2 .

.

APPEND w_d1_2 to w_d1 .
APPEND w_d1 to d2 .

"但作为内表内部组件是没有问题的(因为此时的表头的类型是一个结构,而不是一个内表)
TYPES:BEGIN OF  t3,
  t1s TYPE  t2,
  END OF t3.

"这里一定要加上 occurs 关键字后,才表示定义的变量是一个内表对象,否则表示一个结构对象,原因是TYPE引用的类型本身是一个结构类型,则不是一个内表类型,除非TYPE引用的类型本身是一个内表类型,则就不再需要。
DATA d2 TYPE  t3  OCCURS 10  WITH HEADER LINE.

DATA与WITH HEADER LINE

是否带表头需要在使用DATA定义内表对象时明确指定,如果不指定默认不会带表头的:

.
"定义内表对象,但不带表头
DATA tab1 TYPE itab.
"定义内表对象,带表头
DATA tab2 LIKE tab1 WITH HEADER LINE.

新式内表的定义

TYPES dtype { {TYPE tabkind OF [REF TO] type}
              | {LIKE tabkind OF dobj} }
          [tabkeys]
            [INITIAL SIZE n].

tabkind:

... { {[STANDARD] TABLE}

| {SORTED TABLE}
    | {HASHED TABLE}
    | {ANY TABLE}
    | {INDEX TABLE} } ...

ANY TABLE 与 INDEX TABLE 通用类型只用用在只能用在字段特号与形式参数中:

ABAP 内表 详解

tabkeys:

个第二索引

[{WITH|WITHOUT} FURTHER SECONDARY KEYS ] ...

定义内表数据对象还可以直接采用ABAP字典中的内表类型,或采用字典中的结构体或透明表类型作为内表的行类型

DATA itab { {TYPE [STANDARD]|SORTED|HASHED TABLE OF [REF TO] type}
          | {LIKE [STANDARD]|SORTED|HASHED TABLE OF dobj} }
          [

[ WITH [UNIQUE | NON-UNIQUE]
{{KEY [primary_key [ALIAS key_name] COMPONENTS] comp1 comp2 ...}
| {DEFAULT KEY} } ]"主键索引

[ WITH {UNIQUE HASHED}|{UNIQUE SORTED}|{NON-UNIQUE SORTED}"secondary_key1,第二索引
KEY key_name COMPONENTS comp1 comp2 ...  ]

[ WITHsecondary_key2 ]…"个第二索引

]

[INITIAL SIZE n]
[WITH HEADER LINE]
[VALUE IS INITIAL]

type:可以是基本类型,如DATA: itab TYPE TABLE OF i.

REF TO:表示内表类型为引用类型(该类型内表是用来存储引用的,可指向某个内表)

INITIAL SIZE n:为内表指定初始行数。如果n为0,则会自动分配合适的行数。修改初始内存要求仅用于嵌套表,对于最外层内表没有必要,指定后反可能影响性能,所以一般不用指定。另外,该值对APPEND…SORTED BY…有特殊的作用

tabkind取值如下

2  标准表(STANDARD TABLE,系统为该表的每一行数据生成一个逻辑索引,自己内部维护着行号(Index)的编码。表的键值不唯一,且没有按照表键自动进行排序,支持通过索引访问和键访问两种方式。填充标准表时可以插入到指定位置或现在有行之后,程序对内表的寻址操作可以通过关键字或索引进行。在对表进行插入删除等操作时,各数据行在内存中的物理位置不变,系统仅重新排列各数据行的索引值。当经常用索引访问表的时候就选择标准表。

2  排序表(SORTED TABLE,也有一个逻辑索引,不同之处是排序表总是按其表关键字升序排序后现进行存储,排序内表自己内部也维护着行号的编号,表的键值可以唯一或者不唯一,支持通过索引访问和键访问两种方式。如果经常使用键来访问数据,或者希望数据能够自动排序时,就用排序表。

2  哈希表(HASHED TABLE,哈希表通过哈希函数生成的表键来标识和快速访问表行,哈希表中的表键没有顺序,其值在表中必须唯一,只允许通过表键来访问哈希表。寻址一个数据行的所需时间与表行数无关。如果内表非常大而且希望用主键访问,就用哈希表。

各种类型内表充许的访问方式(索引访问、关键字访问):标准内表主要是索引访问,排序内表主要是Key访问,而哈希内表只能通过Key来访问:

ABAP 内表 详解

ABAP 内表 详解

对于索引类型的内表,当一个行操作语句执行结束后,SY-TABIX将返回该行的索引,成功SY-SUBRC返回0。

虽然索引比使用关键字定位行要快,但在大多数情况下,我们通过关键字定位一行数据,因数据来自数据库,我们不知道数据在哪行。

使用关键字定位一行数据不同内表的效率比较如下:

2  标准表,取决于表的行数,随行数线性增加。(但也可以先进行排序,再明确使用二分搜索查找)

2  排序表,取决于表的行数,随行数对数级增长(系统默认就会使用二分搜索方式来查找)。

2  哈希表,与行数无关,在大数据量的情况下根据关键字查询是最快的

tabkeys表主键:

如果不指定关键字(注:只有标准表可以不用指定索引类型与关键字,因为系统会给一个默认的关键字,即DEFAULTL KEY),则系统会使用默认(标准)关键字,如果指定,则有下列形式:

l  如果内表行结构是结构体,则可以指定结构体中的某几个字段作为内表关键字:

...WITH[UNIQUE|NON-UNIQUE]KEYcomp1 comp2 ...

请注意:多个关键字的排序顺序很重要,会影响到表的排序方式

l  如果内表的整个行都是由基本类型字段组成,或是由基本类型组成的结构类型字段:

...WITH[UNIQUE|NON-UNIQUE]KEYTABLE LINE|TABLE_LINE

TABLE LINE、TABLE_LINE:将表的整行作为Key,则可以使用TABLE_LINE

l  如果不指定任何关键字,则可以使用默认的标准关键字,该项为默认选项:

...WITH[UNIQUE|NON-UNIQUE]DEFAULTKEY...

排序表在指定Key的类型时,可以是UNIQUE也可以是NON-UNIQUE,所以排序内表是否可以存储重复的,则就是看定义时指定的Key类型是UNIQUE还是NON-UNIQUE

标准表只能使用NON-UNIQUE(但可以省略);排序表可以用NON-UNIQUE或UNIQUE(不能省略);哈希表只能使用UNIQUE(不能省略)。

在定义内表时,可以不指关键字,此时使用默认(标准)关键字,即相当于 WITH KEY DEFAULT KEY。如果定义的是STANDARD TABLE,则连WITH KEY DEFAULT KEY选项都可以省略;但如果是SORTED TABLE与HASHED TABLE,如是需要指定为DEFAULT KEY时,不能省略WITH KEY DEFAULT KEY,并且需要确保该内表里有可有作为默认Key的字段——如字符类型字段,否则不能通过编译。

在定义排序表与哈希表时,一定要指定索引类型与关键字(可以指定为WITH KEY DEFAULT KEY),否则编译通过不过。

DEFAULT KEY:默认标准Key为行结构中所有byte-type(x ,xstring, xsequence)类型与character-type(c, d, n, t, string, clike)类型的所有字段,其他一切类型都会被忽略;如果行结构中还有子结构,则该子结构中的所有前面提到的类型字段也会被抽取出来作为Key的一部分;内表类型的字段不会成为默认Key的一部分;如果没有byte-type、character-type类型字段,则默认是不会有Key,:

.
line2-c = 'd'.
line2-line = line1.
"未设置line1-itab,但也能更新,这说明内表字段默认不会作为Key
MODIFY TABLE line2."根据关键字来修改内表
WRITE: / sy-subrc.
LOOP AT  line2 .
  WRITE: / line2-i , line2-c.
ENDLOOP.

虽然数字类型字段默认(DEFUALT KEY)不作为关键字段,但可以使用KEY明确指定;在使用KEY明确指定关键字段时,如果内表行包含结构组件,还可以指定到该结构组件的某个元素作为关键字段:

),
      itab TYPE line0,
      END OF line1.
DATA itab1 TYPE TABLE OF line1 WITH KEY i itab.
DATA itab2 TYPE TABLE OF line1 WITH KEY i itab-i.

使用第二索引

像数据库表一样,内表也可以创建多个索引,内表有三种类型第二索引:

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 fldate bookid
      "第二第二索引:非唯一升序排序索引
      WITH NON-UNIQUE SORTED KEY sort_key
           COMPONENTS customid.

第二索引会影响哪些行将被处理,以及处理顺序:

2  可以在READ TABLE itab, LOOP AT itab, MODIFY itab, DELETE itab内表操作语句中通过WITH [TABLE] KEY ... COMPONENTS或者USING KEY选项指定key_name来使用第二索引

2  可以在INSERT itab与APPEND语句中通过USING KEY选项来使用源内表的第二索引

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 wherecol3=... col4=... .
...
ENDLOOP.

INDEX/ANY TABLE通用型内表

除上面三种标准类型外,还有一般性类型,即索引表(INDEX TABLE)和任意表(ANY TABLE),一般性类型可以用于类型定义中,但不能用于声明一个内表对象,因为它并没有指明任何明确的表类型,因而系统无法确定对其操作方式。一般性类型还可以用于指明字段符号和接口参数的类型,其实际类型可能在运行期内才能够确定。

ABAP 内表 详解

内表整体操作

内表间赋值

两个内表添加使用批量增加代替逐行

不推荐:

LOOP AT int_fligh1.
  APPEND int_fligh1 TO int_fligh2.
ENDLOOP.

推荐:

Append lines of int_fligh1 to int_fligh2.

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

APPEND LINES OF A TO B.

行类型兼容的内表可以使用“=”直接进行赋值,前提是要求行结构可转换,规则参考这里Unicode fragment view of structures

比较内表

EQ, =, NE, <>, ><, GE, >=, LE, <=, GT, >, LT, <

比较标准:

先比较两个内表的行数行,如果行数多的内表就大;如果两个内表的行数相等,将会一行一行、一个字段一个字段的比较,如果字段本身是一个内表类型,则会递归比较;如果不是相等比较时,只要某行某个字段不等就会停止继续向后比较。

排序内表SORT…

可以通过内表的KEY对标准表哈希表按理说哈希表是不能进行排序的,但ABAP里是可以的,与Java不同进行排序:

SORT <itab> [ASCENDING|DESCENDING] [AS TEXT] [STABLE].

SORT itab [STABLE]
          { {[ASCENDING|DESCENDING]
              [AS TEXT]
              [BY {comp1 [ASCENDING|DESCENDING] [AS TEXT]}
                  {comp2 [ASCENDING|DESCENDING] [AS TEXT]}
                  ... ]}
          | {[BY (otab)]} }.

 

该语句默认会按照内表所定义的所有关键字段(即primary table key)来进行排序(在没有使用BY (otab)的情况下),关键字段排序的先后顺序依赖于标准键在内表中的Key定义的顺序。

默认是升序。

由于排序内表具有自动排序功能,因此用SORT关键字对排序内表进行排序没有任何意义,也将会导致程序的编译错误

DATA: itab TYPE HASHED TABLE OF c WITH UNIQUE DEFAULT KEY WITH HEADER LINE.
INSERT '3' INTO TABLE itab.
INSERT '2' INTO TABLE itab.
INSERT '1' INTO TABLE itab.
LOOP AT  itab.
  WRITE: / itab.
ENDLOOP.
SORT itab .
SKIP.
LOOP AT  itab.
  WRITE: / itab.
ENDLOOP.

3

2

1

1

2

3

根据指定的字段进行排序 BY

如果你有一个行类型为结构的内表,则在排序时可以指定排序字段:

BY会取消前面的整体排序字段,即不会再以默认的关键字段来排序,关键字段不现影响排序结构,这些字段可以是任何类型,包括表格。如果指定多个关键字段,则系统首先根据<F1>,然后根据<F2>,以此类推对记录进行排序。系统使用BY 之前指定的排序方式(升序还是降序)将作为 BY 之后指定的所有字段的缺省排序方式(即BY后面没有指定排序方式时会使用前面指定的整体排序方式),且在单个字段之后指定的排序方式将覆盖在 BY 之前指定的这些字段的排序方式。

可以使用 (<name>) 代替<fi>进行动态设置,如果<name>在运行时为空,系统就将其忽略,如果包含无效的组件名,则发生实时错误。对于任何在排序字段中使用的字段,用户都可指定偏移量和长度。

接字母顺序(字符语义)进行排序AS TEXT

CONVERT TEXT text INTOSORTABLECODE hex

根据当用户操作环境来生成字符text所对应的排序字符索引串,此索引串是与用户当前操作的环境有关,如语言、国家等。如中文环境平台下,中文字符串会根据中文的拼音来进行排序,这种排序规则就是在内部采用了另一种专用来排序的编码,hex就是用来存储这种排序编码的。

可以使用SET LOCALE来设置用户所处语言环境

SET LOCALE LANGUAGE<lg> [COUNTRY<cy>]

修改当前用户所处的语言环境

The fields <lg>, <cy>, and <m> must be of type C and must have the same lengths as the keyfields of table TCP0C. Table TCP0Cis a table, in which the text environment is maintainedplatform-dependent.

SET LOCALE只影响SORT ... AS TEXT, TRANSLATE ... TO

SET LOCALE LANGUAGE ''

当lg为空时,会重新设置为登录时的语言环境

SORT <itab> ... AS TEXT ... .

根据用户当前所处的语言环境来进行排序(如中文环境下,中文字符按拼音的排序规则来进行排序),如果不指定该选项,则会默认使用Unicode排序

如果待排序的字符串只有ASCII字符,则没有必要使用该选项

publicclass T {

publicstaticvoid main(String[] args) throws UnsupportedEncodingException {

String str = "的";

byte[] b = "的".getBytes("utf-8");

for (byte c : b) {

System.out.print(byteToHex(c));

}

}

publicstatic String byteToHex(byte b) {

return Integer.toHexString((b & 0x000000FF) | 0xFFFFFF00).substring(6)

.toUpperCase();

}

}

E79A84

ABAP 内表 详解

ABAP 内表 详解

DATA: BEGIN OF line,
  c TYPE string,
  b TYPE xstring,
  x TYPE xstring,
  END OF line.
"在转换之前先一定要设置当前所要使用的语言环境
SET LOCALE LANGUAGE '1' COUNTRY 'CN'.
DATA: itab LIKE STANDARD TABLE OF line WITH HEADER LINE WITH NON-UNIQUE KEY c.

PERFORM append USING '的'.
PERFORM append USING '边'.
PERFORM append USING '二'.
PERFORM append USING '安'.
PERFORM append USING '长'.

WRITE: / '--原始顺序--'.
LOOP AT itab.
  WRITE: / itab-c,itab-b,itab-x.
ENDLOOP.
SKIP.
SORT itab BY c.
WRITE: / '--按字符的Unicode编码进行排序--'.
LOOP AT itab.
  WRITE: / itab-c,itab-b,itab-x.
ENDLOOP.
SKIP.
SORT itab BY b.
WRITE: / '--直接按字符的UTF8编码所对应的数字进行排序--'.
LOOP AT itab.
  WRITE: / itab-c,itab-b,itab-x.
ENDLOOP.
SKIP.
SORT itab BY c AS TEXT.
WRITE: / '--按中文语义(拼音)进行排序--'.
LOOP AT itab.
  WRITE: / itab-c,itab-b,itab-x.
ENDLOOP.
SKIP.
WRITE: / '--按中文字符所对应的排序Key来进行排序--'.
SORT itab BY x.
LOOP AT itab.
  WRITE: / itab-c,itab-b,itab-x.
ENDLOOP.

FORM append  USING  value(p_0059).
  itab-c = p_0059.
  DATA : l_con TYPE  REF  TO  cl_rpe_convert.
  CREATE  OBJECT l_con.
  CALL METHOD l_con->string_to_xstring
    EXPORTING
      input  = itab-c
    IMPORTING
      output = itab-b.
  CONVERT TEXT itab-c INTO SORTABLE CODE itab-x.
  APPEND  itab.
ENDFORM.

--原始顺序--

的 E79A84 C6D501050105

边 E8BEB9 C57301050105

二 E4BA8C C77201050105

安 E5AE89 A901050105

长 E995BF C5F401050105

----按字符的Unicode编码进行排序----

二 E4BA8C C77201050105

安 E5AE89 A901050105

的 E79A84 C6D501050105

边 E8BEB9 C57301050105

长 E995BF C5F401050105

--直接按字符的UTF8编码所对应的数字进行排序--

二 E4BA8C C77201050105

安 E5AE89 A901050105

的 E79A84 C6D501050105

边 E8BEB9 C57301050105

长 E995BF C5F401050105

--按中文语义(拼音)进行排序--

安 E5AE89 A901050105

边 E8BEB9 C57301050105

长 E995BF C5F401050105

的 E79A84 C6D501050105

二 E4BA8C C77201050105

--按中文字符所对应的排序Key来进行排序--

安 E5AE89 A901050105

边 E8BEB9 C57301050105

长 E995BF C5F401050105

的 E79A84 C6D501050105

二 E4BA8C C77201050105

稳定排序STABLE

SORT <itab> ... STABLE.

如果对于数组中出现的任意a[i],a[j](i<j),其中a[i]==a[j],在进行排序以后a[i]一定出现在a[j]之前,则认为该排序是稳定的。(相等的数据不会再交换位置,排序后仍然后保持原始顺序)。

不知道为什么,去掉 STABLE 选项好像还是稳定的,难道默认就是稳定排序?

DESCRIBETABLE获取内表属性

DESCRIBETABLE

获取内表数据行数 Lines()

... lines( arg ) ...

The function lines determines the number of lines in an internal table. The argument arg must be an internal table.

内表行操作

单行操作

ABAP 内表 详解

多行操作

ABAP 内表 详解

适用所有类型内表的行操作

在该节中列出的操作适用所有类型的内表。如果你在操作之前知道内表的类型,请使用合适的操作,比如,使用 APPEND…TO 语句填充索引内表,使用 INSERT…INTO TABLE 来填充Hash表或通用性类型(ANY TABLE、INDEX TABLE),这样效率会高一些。

INSERT向表中插入行

INSERT wa|{INITIAL LINE}|{LINES OF jtab [FROM idx1] [TO idx2] [USING KEY key_name|(name)]} 
INTO {TABLE itab}
{ ASSIGNING <fs> [CASTING] }|{ REFERENCE INTO dref }.

不能向排序表中插入重复的数据,否则抛异常。

如果向哈希表中插入重得的数据,不会起作用,也不会抛异常。

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

插入一行

INSERT <line> INTO TABLE<itab>.

<line>可以是一个工作区或者是 INITIAL LINE。

如果向一个 unique key 内表中插入重复的数据行,则SY-SUBRC to 4。

向不同类型表中插入的情况:

2  标准表:会在内表最后新增行,与 APPEND 效果一样。

2  排序表:会根据表关键字段插入到合适的位置。如果是一个 non-unique 内表,会将重复的行插入到已经存在数据行的前面。所花费的时间会随着表中的数据增加成对数形式的增加。

2  哈希表:使用哈希算根据表关键字计算出所插入的位置,哈希表不会因为数据行的增加而速度减慢。

插入多行FROM…TO

INSERT LINES OF <itab1> [FROM <n1>] [TO <n2>] INTO TABLE<itab2>.

<itab1> and <itab2>要具有兼容的行类型。系统将使用单条插入规则一条条插入到<itab2>中。如果<itab1>是一个索引类型的表,则可以指定待插入的第一行<n1>与最后一行<n2>数据的索引。

取决于表格大小和插入地点的不同,用该方式将一个表格插入到另一个中的速度比在循环中逐行进行插入要快近20倍。

..line-col3 = 'b'.
  APPEND line TO jtab.
ENDDO.
"会将重复的行插入到已经存在数据行的前面
INSERT lines of itab INTO TABLE jtab.
LOOP AT jtab INTO line.
  WRITE: / sy-tabix, line-col1, line-col2,line-col3.
ENDLOOP.

1           1           1  a

2           1           1  b

3           2           4  a

4           2           8  b

COLLECT合并

COLLECT [<wa>INTO] <itab>{ ASSIGNING<fs> [CASTING] } | { REFERENCEINTO dref }.

<itab>必须是扁平结构,所有其他非关键字段的字段必须是数字类型(I、F、P):

.
itab-col3 = .
itab-col3 = 'c'.
"编译出错:非关键字段必须是 I P F 数字类型
*COLLECT itab INTO itab.

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

如果仅使用 COLLECT 语句填充内表,则不会出现重复条目,因此适用于统计表的构造。

不同类型的内表统计情况:

ü  标准表:系统会顺序查找是否已经存在的行,所花时间会随着表的行数线性增加,如果原始表里存在重复的行,则只会与第一行合并。SY-TABIX存储了COLLECT操作所对应的插入或合并索引号。

ü  排序表:系统使用二分查找法搜索已存在的行,索引的运行的时间会随着行数的增加成对数级的增加。SY-TABIX存储了COLLECT操作所对应的插入或合并索引号

ü  哈希表:系统使用哈希算法查找已存在的行,在使用COLLECT后,SY-TABIX的值还会是0,因为哈希表没有索引。

) ) .
.
.
COLLECT line INTO itab.
WRITE / sy-tabix.
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2, line-col3.
ENDLOOP.

1

2

1

abc 12         10

def 34          5

READ 读取行

READ TABLE itab { 
{FROM wa [USING KEY key_name|(name)]}
| {WITH TABLE KEY [key_name|(name) COMPONENTS] {comp_name1|(name1)} = dobj1 {comp_name2|(name2)} = dobj2 ...}
| WITH KEY {comp1 = dobj1 comp2 = dobj2 ... [BINARY SEARCH]} | {key_name|(name) COMPONENTS comp1 = dobj1 comp2 = dobj2 ...}
|INDEX idx [USING KEY key_name|(name)] }
{INTO wa [[COMPARING { {comp1 comp2...}|{ALL FIELDS}|{NO FIELDS} }] [TRANSPORTING{ {comp1 comp2...}|{ALL FIELDS} }]]}| {ASSIGNING<fs> [CASTING]} | {REFERENCE INTO dref} | {TRANSPORTING NO FIELDS}..

comp1 comp2 ...
... { comp_name[-sub_comp][{+off(len)}|{->attr}] } | {(name)} ...

如果未指定USING KEY选项,则默认会使用primary table key。

如果内表定义了第二排序索引sorted secondary key,则可以使用 USING KEY 选项来指定这个第二排序索引,即读取时,根据此第二排序Key排序之后的索引来读取,但不能使用secondary hashed key.

如果内表的secondary key 存在,使用了USING KEY时,INDEX选项可以应用到不同类型的内表中(比如可以给Hash内表创建一个第二排序索引sorted secondary key,则在读取此Hash内表时,可以使用索引INDEX方式来读取) 

sy-subrc

sy-tabix

0

找到记录

sy-tabix为主或第二索引值primary or secondary table index used,如果是hash key,则sy-tabix为0

2

找到记录,但COMPARING时相应字段不同

sy-tabix为主或第二索引值primary or secondary table index used,如果是hash key,则sy-tabix为0

4

记录没找到,且未读取到内表尾部

如果READ TABLE语句中明确地使用BINARY SEARCH方式读取、或者读取时使用了USE KEY、WITH [TABLE] KEY key_name选项明确的指定通过UNIQUE SORTED、NON-UNIQUE SORTED类型的第二辅助索引来方式来读取的、又或者读取的内表本身就是排序类型,则sy-tabix的值为待查记录在该内表中本应该出现的位置索引,除些之外,sy-tabix的值是不确定的

8

记录没有找到,且读取到内表尾部了
如果通过了二分搜索,且探索到尾部都还没有搜到时,sy-tabix的值为rows + 1

指定搜索关键字段

搜索关键字段可以是表关键字段,也可也是其他非表关键字段。

如果是non-unique的内表,有重复行时,会返回第一条数据。

使用表关键字段进行读取

READ TABLE<itab>FROM <wa><result>.

或者

READ TABLE <itab>WITH TABLE KEY<k1> = <f1> ...<kn> = <fn><result>.

第一种的<wa>必须与行类型兼容,以表关键字为查找条件,且值来自<wa>,如果相应关键字段的值为空,则匹配所有的记录,如果所有关键字都为空,则会读取第一行

第二种也是使用整个表关键字段进搜索,k1…kn可以动态指定(如(<ni>) = <fi>.)。

如果在读取时,未使用第二辅助索引Key,而是使用的默认的primary table key ,则不同的类型的内表读取的方式不一样:

ü  标准表:顺序搜索,查找时间会随着条目的增加而线性增加

ü  排序表:二分查找,查找时间会随着条目的增加而对数级增加

ü  哈希表:使用哈希算法进行查询,查找时间不依赖于条目数

,
      END OF line.
DATA itab LIKE line OCCURS 10 WITH HEADER LINE.
DO 5 TIMES.
  line-col1 = sy-index.  line-col2 = SQRT( sy-index ).
  APPEND line TO itab.
ENDDO.

CLEAR: itab,line.
itab-col1 = '2'.
READ TABLE itab INTO line.条件来自表头关键字段,并将查找到的结果存入到工作区
WRITE: / sy-subrc, itab-col2, line-col2.

CLEAR: itab,line.
itab-col1 = '2'.
READ TABLE itab.条件来自表头关键字段,并将查找到的结果存入表头
WRITE: / sy-subrc, itab-col2, line-col2.

0           0.00000           1.41421

0           1.41421           0.00000

使用其他关键字段进行读取

如果使用其他非表关键字段为条件进行搜索时,可以使用以下语句:

READ TABLE<itab>WITH KEY= <key><result>.

或者

READ TABLE <itab> WITH KEY<k1> = <f1> ... <kn> = <fn><result>.

在第一个语句中,key是一个工作区,并且整个内表的行的所有字段都会作为搜索条件。注:一定是整行,而不是内表本身那些关键字段所构成的字段,也就是说与内表本身关键字段没有任何关系,请看下面示例:

.
.
.
.
.
.
WRITE: / sy-subrc, itab2.

在第二个语句中,这里的 k1…kn 不一定是内表中真正的关键字段,只要是内表行组件即可。如果 k1…kn 要到运行时才知道,则可以使用(' key ') = <f>的格式来动态指定要比较的字段,如果 key 为空,则会忽略比较。

以上二种两种方式对于所有表都是顺序搜索,所需时间随着表的数据量增加或线性增加。

以行首字段搜索

要将内表的行首定义为关键字,请使用 WITH KEY 选项

READ TABLE <itab>WITH KEY<k><result>.

<k>不能包含内表或包含内表的结构。

.
WRITE: / sy-subrc, line-c.

0    a

USING KEY

READ TABLE itab {FROM wa [USING KEY key_name|(name)]}

DATA: sflight_tab TYPE HASHED TABLE OF sflight
                  WITH UNIQUE KEY primary_key  COMPONENTS carrid connid fldate
                  WITH NON-UNIQUE SORTED KEY occupied_seats COMPONENTS seatsocc,
      sflight_wa  LIKE LINE OF sflight_tab.
...

DO 10 TIMES.
  "使用排序第二索引,这样即使是Hash类型的内表,也可以使用INDEX方式来读取Hash内表
  READ TABLE sflight_tab
       INDEX sy-index USING KEY occupied_seats
       INTO sflight_wa.
  ...
ENDDO.

指定额外处理选项"><result>指定额外处理选项

你可以指定一些额外的选项来让系统如何处理查找到数据。

指定工作区

你可以将找到的数据行存储到一个带有<result>选项的工作区中:

READ TABLE <itab><key> INTO <wa>[COMPARING <f1><f2> ...|ALL FIELDS]

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

这里的<fi>可以是动态指定的((<ni>))

COMPARING比较读取的单行内容

系统根据<key>(关键字段)读取指定的单行并先存储到<wa>工作区中,读取行之后,将表与工作区<wa>中的相应组件进行比较。

... <F1> ...<fn>表示只比较指定的字段,

... ALL FIELDS表示比较所有组件

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

.
  . .
READ TABLE itab FROM line INTO line COMPARING col2.
WRITE: 'SY-SUBRC =', sy-subrc.
WRITE: / line-col1, line-col2.

SY-SUBRC =     2

2           4

.
"只要根据关键字或索引条件在内表中读取到相应数据,不管该数据行是否
"与COMPARING 指定的字段相符,都会覆盖存储到工作区中。
READ TABLE itab INTO line INDEX 4 COMPARING col1 col2.
WRITE: / sy-subrc, sy-tabix,line-col1,line-col2,line-col3.
CLEAR: line-col3.
"也可以使用关键字KEY来读取指定行再进行比较
READ TABLE itab INTO line WITH KEY col1 = 4 col2 = 16 COMPARING col1 col2.
WRITE: / sy-subrc, sy-tabix,line-col1,line-col2,line-col3.

2           4           4          16          64

0           4           4          16          64

TRANSPORTING读取一行的部分字段

系统根据<key>(关键字段)条件查找对应的条目后,只将<result>中指定的组件字段存储到工作区域中。

... NO FIELDS表示不传输任何组件,此种情况下,READ语句只影响系统字段 SY-SUBRC 和 SY-TABIX(前提条件是索引表),并且在TRANSPORTING NO FIELDS情况下,如果指定了<wa>,则会忽略掉。

.
  INTO line TRANSPORTING col2.主键没有被传输
WRITE: 'SY-SUBRC =', sy-subrc,
/ 'SY-TABIX =', sy-tabix.
WRITE: / line-col1, line-col2.

SY-SUBRC =     0

SY-TABIX =          3

0           9

.
   TRANSPORTING NO FIELDS.
WRITE: 'SY-SUBRC =', sy-subrc,
/ 'SY-TABIX =', sy-tabix.

SY-SUBRC =     0

SY-TABIX =          4

使用字段符号

ABAP 内表 详解

你可以将查到的数据行赋值给指定的字段符号:

READ TABLE <itab><key>ASSIGNING<FS>.

 

获取更多的信息,请参考使用字段符号进行访问

.
   .
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

1           1

2         100

3           9

4          16

MODIFY 修改行

MODIFY { 
TABLE itab [USING KEY key_name|(name)] | {itab INDEX idx [USING KEY key_name|(name)]} | {itab [USING KEY loop_key]} } FROM wa [TRANSPORTINGcomp1 comp2...] [{ASSIGNING <fs> [CASTING]} | {REFERENCE INTO dref}]
|itab FROM wa [USING KEY key_name|(name)] TRANSPORTING comp1 comp2... WHERE log_exp|(cond_syntax) }.

comp1 comp2 ...
... { comp_name[-sub_comp][{+off(len)}|{->attr}] } | {(name)} ...

修改单条记录(TABLE KEY)

MODIFY TABLE <itab>[USING KEY key_name|(name)]FROM<wa> [TRANSPORTING<f1><f2> ...].

这里的<wa>扮演双重身份,不仅指定了要修改的行(条件),还包括要修改的新的值。系统以整个表的所有关键字段来搜索要修改的行。

USING KEY:如果未使用此选项,则会使用默认的主键primary table key来修改相应行

如果找到要修改的行,则将<wa>中所有非关键字段的内容拷贝到对应的数据行中对应的字段上, SY-SUBRC设置为 0,否则 SY-SUBRC 设置为4。如果是 NON-UNIQUE 类型的表,且找到多条时只修改第一条数据。

可以使用 TRANSPORTING 选项修改部分非关键字段。

Fi可以是动态指定(<ni>) ,如果ni 为空,则运行时会忽略。

.
MODIFY TABLE itab FROM line.
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

1           1

2         100

3           9

4          16

修改多条记录(WHERE)

MODIFY <itab> FROM <wa> TRANSPORTING<f1><f2> ... WHERE <cond>.

该语句会修改满中条件的多条件数据。逻辑表达式<cond>中的各子表达式的第一个操作数必须是内表行结构的组件。

这里的TRANSPORTING 是必须的,与上面MODIFY中的TRANSPORTING不一样。

如果是标准表,可以在TRANSPORTING后面指定修改字段为表关键字段,但排序表与哈希表则不能修改关键字段。

如果至少有一条数据被成功修改了,则SY-SUBRC为0,否则为4。

.
MODIFY itab FROM line TRANSPORTING col2 WHERE ( col2 > 1 ) AND ( col1 < 4 ).
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

1           1

2         100

3         100

4          16

DELETE 删除行

DELETE { {TABLEitab {FROM wa [USING KEY key_name|(name)]} | {WITH TABLE KEY [key_name|(name) COMPONENTS] {comp_name1|(name1)}=dobj1 {comp_name2|(name2)}=dobj2...}} | {itab INDEX idx [USING KEY key_name|(name)]} | {itab [USING KEY loop_key]}
| itab [USING KEY key_name|(name)] [FROM idx1] [TO idx2] [WHERE log_exp|(cond_syntax)]
| ADJACENT DUPLICATES FROM itab [USING KEY key_name|(name)] [COMPARING {comp1 comp2 ...}|{ALL FIELDS}]... }

comp1 comp2 ...
... { comp_name[-sub_comp][{+off(len)}|{->attr}] } | {(name)} ...

循环中插入或删除行

最好不要在循环中插入或删除行,因为可能会发生不必要的问题:插入操作会使插入位置后面的行的sy-tabix 都加1(只针对索引表),删除则会是被删除行后面所有行的索引都减1;如果是插入,则下次循环还是从当前被遍历行的后面开始接着遍历,但索引增加1了;但如果是删除的是当前遍历的行,则下次删除还是继续接着删除下一行数据,并且删除后下次循环的索引还是与上次一样(所以能连续删除,不会隔行删除) ,

循环中插入行请参见这里

循环中删除行请参见这里

下面也能删除所有行:

.
  DELETE itab_person.
ENDLOOP.

删除单行(TABLE KEY)

DELETE TABLE<itab>FROM<wa>.

或者

DELETE TABLE <itab> WITH TABLE KEY <k1> = <f1> ... <kn> = <fn>.

两个语句都是根据表的关键字段进行删除的,第二种要将所有表关键字段写上,不同第一种的是可以使用动态的字段名。

如果成功删除,则SY-SUBRC设置为0,否则为4。如果是 non-unique 内表,且满足条件的有多条件数据时,只会删除第一条。

.
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

2           4

4          16

删除多行(WHERE)

DELETE<itab>WHERE<cond>.

如果至少有一条数据被成功删除,则SY-SUBRC为0,否则为4。

.
  INSERT line INTO TABLE itab.
ENDDO.
DELETE itab WHERE ( col2 > 1 ) AND ( col1 < 4 ).
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

1           1

4          16

删除邻近重复行(ADJACENT DUPLICATE)

DELETE ADJACENT DUPLICATES FROM <itab>

[COMPARING<f1><f2> ...

|ALL FIELDS].

系统从内表<itab>中删除所有邻近重复条目。

在以下情况下表示记录重复:

_      如果没有 COMPARING 选项,则所内表有标准关键字段的内容相同时。

_      如果有 COMPARING 选项.... COMPARING <F1><F2> ... ,指定字段<F1><F2> ... 的内容必须相同才算重复。也可以通过写入 (<name>) 代替<F1>在运行时在括号中动态指定字段名。如果<name>在运行时为空,则系统将其忽略。如果包含无效的组件名,则会发生实时错误。

_      如果用 COMPARING 选项.... COMPARING ALL FIELDS ,内表行所有字段的内容必须相同时才算重复。

如果系统找到并删除至少一个重复条目,则将 SY-SUBRC 设置为0。否则,将其设置为4。

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

.
. . . . . . . .
.
.
LOOP AT itab INTO line.
  WRITE: /42 line-col1, line-col2.
ENDLOOP.

1  A         1  A          1  A          1  A

1  A         1  B          2  B          2  B

1  B         2  B          3  B          5  A

2  B         3  B          4  B

3  B         4  B          5  A

4  B         5  A

5  A

LOOP在循环中处理行

LOOP ATitab {INTO wa}|{ASSIGNING <fs> [CASTING]}|{REFERENCE INTO dref}|{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,如:

INTO TABLE hash.
LOOP AT  hash.
  WRITE: / sy-tabix, hash.
ENDLOOP.

0           4

0           2

0           3

0           1

可以嵌套LOOP,当进入或离开某层LOOP时,SY-TABIX会根据着相应变化。在ENDLOOP后面,如果至少有一条数据被处理,则SY-SUBRC 为0,否则为4。

如果循环的是哈希表,则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.
SUM

要在循环处理期间计算内表中数字字段的内容之和:

SUM.

系统只能在 LOOP - ENDLOOP 块中处理该语句。

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

如果某个内表行的组件是另一个表格,则不要使用 SUM 语句。

.
 .
  APPEND line TO itab.
ENDDO.
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
  "统计后会将统计的结果临时存入工作区
  SUM.
  WRITE: / line-col1, line-col2.
ENDLOOP.
SKIP.
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

1           1

6          14

2           4

6          14

3           9

6          14

1           1

2           4

3           9

AT

AT <line>.

<statement block>

ENDAT.

<line>

含义

FIRST

内表的第一行时触发

LAST

内表的最后一行时触发

NEW <f>

相邻数据行中相同<f>字段构成一组,在循环到该组的开头时触发

END Of <f>

相邻数据行中相同<f>字段构成一组,在循环到该组的最末时触发

在使用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 <f2>. ...... ENDAT.

.......

<single line processing>

.......

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

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

AT LAST. .... ENDAT.

ENDLOOP.

<single line processing>块专门用来处理所有非分组字段。你可以处理所有分组字段,但只要出现时,请按照以上顺序来书写代码块。

可以使用动态方式 ('F1') 来设置字段名称。

========================================================

如果循环的内表不是自己定义的,有时无法将分组的字段按顺序声明在一起,所以需要自己实现这些功能,下面是自己实现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_datawhere 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 .不是分组中最末行

"."当前行已是内表中最后一行
        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.

========================================================

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

在输出时最好将使用在AT......ENDAT语句中的字段输出放在最前面,并且按照在这些语句的使用顺序来顺序输出,而其他字段放在后面进行输出。

) TYPE c,
      END OF line.

) 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

,
      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.
    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  ****.**.**

ABAP 内表 详解

另外,其实这个统计与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前面的字段也全都用在了分组意义当中了。

适用索引表的行操作

这一节中所有操作只适用于索引表(标准表与排序表)

APPEND 附加行

APPEND wa|{INITIAL LINE} | {LINES OF jtab [FROM idx1] [TO idx2] [USING KEY key_name|(name)]}
       TO itab
[SORTED BY comp]
[{ ASSIGNING <fs> [CASTING] } | { REFERENCE INTO dref }]

l  APPEND/INSERT操作不能用于Hash表

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

附加单行

APPEND  {<wa>|INITIAL LINE} [TO <itab>].

SY-TABIX存储了附加行所在的索引号。

如果itab带有表头,则可以省略TO <itab>选项,直接使用 APPEND<itab>

 

 

.
APPEND line1 TO tab1.
line2-field1 = 'B'. line2-field2 = tab1.
APPEND line2 TO tab2.
LOOP AT tab2 INTO line2.
  WRITE: / line2-field1.
  LOOP AT line2-field2 INTO line1.
    WRITE: /2 line1-col1, line1-col2, line1-col3.
  ENDLOOP.
ENDLOOP.

A

abc 12          3

def 34          5

B

ghi 56          7

jkl 78          9

附加多行FROM… TO

APPENDLINESOF<itab1> [FROM<n1>] [TO<n2>] TO<itab2>.

如果省略 FROM 或 TO ,则<itab1>可以是任意类型的表,但行类型要与<itab2>兼容,且<itab2>只能是索引表;如果没有省略,则<itab1>只能是索引类型的内表(索引表、标准表)

该方法比在循环中一行行附加要快3到4倍。语句运行完后,SY-TABIX存储了最后一个附加行所在的索引。与单选一样,对于排序表,不能违反唯一约束(唯一索引排序表)与升序排序规则,否则运行时会报错。

.
  APPEND line TO jtab.
ENDDO.
APPEND LINES OF jtab FROM 2 TO 3 TO itab.
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

1          1

2          4

3          9

2          8

3         27

以排序方式附加

APPEND <wa> TO <itab> SORTED BY <f>.

在向内表加入数据行时会根据<f>的降序位置来插入到相应位置,不一定是最后位置。注,不能指定排序方式,默认就是降序,另外不能指定多个字段。而且该选项只适合于标准表,不能用于排序表。

由于效率方面的原因,建议用 SORT 语句对表格进行排序。

,
         column1 . itab-column2 = . itab-column3 = .
. itab-column2 = . itab-column3 = .
. itab-column2 = . itab-column3 = .
APPEND itab SORTED BY column2.
LOOP AT itab.
  WRITE: / itab-column2.
ENDLOOP.

8

5

如果使用 SORTED BY 选项,表格只能包含 OCCURS 参数中指定的行数。如果添加的行数比指定的要多,则丢弃最后一行(这对于创建限定长度的排序列表非常有用,比如取最大前十条记录)。

APPEND …SORTED BY…

APPEND <wa>TO <itab> SORTED BY <f>.

该语句只适用于standard table。新附加行不一定会附加到内表<itab>的尾部,在插入之时会对字段<f>进行比较(采用降序比较)找到插入位置,将超过n(n为内表定义语句中的INITIAL SIZE 选项中所指定的n)行之外的最后一行删除,只保留前n条记录。

注:此种APPEND只适用于标准内表。一种用来取前n条应用(根据字段<f>进行降序排序),在定义内表<itab>时,应在INITIAL SIZE 选项中指定所取的前n条的值,并且在使用过程,不要与APPEND <wa> TO <itab>混用,并且在使用前,<itab>需要为空,否则会混乱。

对后面的APPEND语句产生影响:保留前2名的记录
.
APPEND line TO itab SORTED BY col2.
LOOP AT itab INTO line.
  WRITE: / line-col2.
ENDLOOP.

ABAP 内表 详解

USING KEY

.
APPEND itab.

APPEND LINES OF itab FROM 2 to 3  USING KEY  primary_key to itab2.
LOOP AT itab2.
  WRITE: itab2-a.
ENDLOOP.
CLEAR: itab2[].

NEW-LINE.
"按第二索引sort_key的排序方式(升序),取index 2 到 3 的记录,并附加到 itab2中
APPEND LINES OF itab FROM 2 to 3  USING KEY sort_key to itab2.
LOOP AT itab2.
  WRITE: itab2-a.
ENDLOOP.

"下面语句出错: hash key不支持此种用法,原因是 hash 本身没有索引概念可言
"APPEND LINES OF itab FROM 2 to 3  USING KEY hash_key to itab2.

6           1

6           3

INSERT插入到指定的索引位置

INSERT wa|{INITIAL LINE}|{LINES OF jtab [FROM idx1] [TO idx2] [USING KEY key_name|(name)]} 
INTO {itab INDEX idx}|{itab} 
{ ASSIGNING <fs> [CASTING] }|{ REFERENCE INTO dref }.

插入单行

INSERT {<wa>|INITIALLINE}  INTO <itab> [INDEX <idx>].

如果不使用 INDEX 选项,则将新的行插入到当前行的前面(索引为当前行索引),则当前行及后面的所有行的索引都会向后移一个位置,且索引会自动加1。

如果itab是带表头的索引类型内表,可以省略INTO <itab>、INDEX <idx>选项,直接使用INSERT<itab>,但此语句只可以在LOOP AT <itab>(此时不能使用USING KEY选项)循环中直接使用(这与APPEND不太一样,APPEND没有这样的限制),并且新插入的行会放在当前循环行的前面

如果使用 INDEX 选项,则将新行插入到有索引<idx>的行之前。插入之后,新条目索引为<idx>,后面所有行索引加 1(注:插入操作不影响当前正在循环的SY-TABIX原有的值)。如果表格包含<idx> - 1 条目,系统将新条目附加到最后的现有表格行之后。如果表格的条目小于<idx> - 1,系统无法插入条目并将 SY-SUBRC 设置为4。

只能在 LOOP - ENDLOOP 循环,可以省略 INDEX 选项,表示在当前循环行前插入新行(此时<idx>隐含设置成SY-TABIX),下次循环还是会从当前循环行的下一行开始处理,即不会影响循环,但被插入的行不会被循环到了。

不能向 unique 排序表中插入重复值,另外向排序表中插入值时不能违反排序表的默认排序规则,否则运行时出错。

循环中插入或删除行:

.
 .
  了
* sy-tabix. * sy-tabix.
  的数据行,删除后下次循环的索引还是与上次相同
  .
    DELETE itab INDEX sy-tabix.
  ENDIF.
ENDLOOP.
LOOP AT itab INTO line.
  WRITE: / sy-tabix, line-col1, line-col2.
ENDLOOP.

1           1

3           3

1           3           5

2           1           1

3           9          15

4           2           4

1           3           5

插入多行FROM…TO

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

如果省略 FROM 或 TO ,则<itab1>可以是任意类型的表,但行类型要与<itab2>兼容;如果没有省略,则<itab1>只能是索引类型的内表(索引表、标准表)。

依赖于数据量与插入的位置,这种插入比在循环中一条条插入要快。

.
  .
    .
LOOP AT jtab INTO line.
  WRITE: / sy-tabix, line-col1, line-col2.
ENDLOOP.

1           2           4

2           3           9

3           1           1

4           2           8

5           3          27

READ读取指定索引位置上的行

READ TABLE最全语法规则表请参考这里

READ TABLE <itab> INDEX <idx> <result>.

<result>请参考这里。该语句只会读取<idx>所在位置的行,只会读取一行,这与使用 key 为条件来读取是一样的(以key为条件读取时可能会出现多条,但只取第一条)。

根据索引来读取数据要比使用Key来读取行速度要快。

这里的TABLE关键字不能省略,这与DELETEMODIFY两个关键字不太一样,这两个关键字在对带有表头的索引类型内表进行操作时,语句中没有TABLE关键字。

可以省略INDEX <idx>选项,直接使用READ TABLE <itab>,此时会默认从 itab 内表的表头<wa>作为条件,此时语句即为省略了FROM <wa>选项的READ TABLE <itab> FROM <wa>语句。如果<wa>中相应的关键字段为空,则会匹配所有记录,如果所有关键字段为空,则直接读取第一行数据

如果找到数据行则SY-SUBRC为0,且SY-TABIX存储当前找到的数据行索引,如果未找到,则SY-SUBRC为非0。

* sy- ASSIGNING <fs> .
WRITE:/ sy-subrc, sy-tabix.
WRITE: / <fs>-col1, <fs>-col2.

0           7

7          14

在索引表中进行二分搜索

READ TABLE <itab> WITH KEY = <f><result>BINARY SEARCH.

READ TABLE <itab> WITH KEY <k1> = <f1> ... <kn> = <fn><result>

BINARY SEARCH.

 

BINARY SEARCH选项只能在使用key方式读取的语句,不能以index方式读取。

如果是以key的方式读取标准表时,可以用二分法搜索代替顺序搜索,但对于标准表,必须先接照查找的关键字进行升序排序后有意义。

对于排序表,使用key进行读取行时,不需要先使用Sort关键字进行排序(也不能对排序表再进行排序,否则会出错),但在READ语句中可以使用BINARY SEARCH选项。

另外,哈希表,则不能使用二分搜索选项BINARY SEARCH(原因可以是哈希比二分搜索要快吧),但能使用SORT语句对Hash表进行排序,而且具有排序效果(这个比较意外,有点像Java的Treemap集合了):

.
.
INSERT  itab INTO TABLE itab.
LOOP AT  itab .
  WRITE: / itab-i.
ENDLOOP.
"可以对Hash表进行排序
SORT itab DESCENDING.
SKIP.
LOOP AT  itab .
  WRITE: / itab-i.
ENDLOOP.
"但不能使用BINARY SEARCH选项
*READ TABLE itab WITH TABLE KEY i = 2 BINARY SEARCH.

         1

         2

 

         2

         1

.
   INTO line BINARY SEARCH.
WRITE: 'SY-SUBRC =', sy-subrc.

SY-SUBRC =     0

在内表中搜索字符串

SEARCH <itab> FOR <str><options>.

将会搜索整个内表行,如果找到,SY-SUBRC为0,SY-TABIX存储找到的字符串所在行索引,SY-FDPOS存储了所查找到的字符串位置在内表行内(前面所有字段都会算在里面)的位置,具体算法请参考Search搜索字符串

各字段只能是C、N、D、T固定长度的字符类型字段(书上说任何类型都可能,但试了一下String类型也不行)。<str>支持的模式与<options>选项可以参看Search搜索字符串

) ) )  TIMES.
  line-index = sy-index.
  num = sy-index.
  CONCATENATE 'aastring' num INTO line-text.
  APPEND line TO itab.
ENDDO.

LOOP AT itab INTO line.
  WRITE: / line-index,line-text.
ENDLOOP.
SEARCH itab FOR 'string02' AND MARK.
READ TABLE itab INTO line INDEX sy-tabix.
WRITE: / sy-subrc,sy-fdpos,line-index,line-text.

01 aastring01

02 aastring02

03 aastring03

0      4  02 aaSTRING02

如果将上面index字段声明在text字段后面,则上面的sy-fdpos的结果则为2。

MODIFY修改指定索引位置上的行

MODIFY { 
TABLE itab [USING KEY key_name|(name)] | {itab INDEX idx [USING KEY key_name|(name)]} | {itab [USING KEY loop_key]} } FROM wa [TRANSPORTINGcomp1 comp2...] [{ASSIGNING <fs> [CASTING]} | {REFERENCE INTO dref}]
|itab FROM wa [USING KEY key_name|(name)] TRANSPORTING comp1 comp2... WHERE log_exp|(cond_syntax) }.

comp1 comp2 ...
... { comp_name[-sub_comp][{+off(len)}|{->attr}] } | {(name)} ...

修改单行

MODIFY<itab>[INDEX<idx>] FROM<wa>[TRANSPORTING<f1><f2> ... ].

如果没有 INDEX 选项,你只能在循环中使用该语句,在此种情况下,每次循环中<idx>会默认设置为SY-TABIX,即当前遍历的号行。

如果修改的标准表,则关键字段是可以被修改的。

当修改的是排序表时,你不能将关键字段修改成其他值,否则运行时出错。在修改排序表时,如果没有使用TRANSPORTING选项,则<wa>的key字段必须与要修改的行key字段值相同;如果指定了TRANSPORTING选项,则该选项后面不能接key字段,但此时<wa>中的key字段会忽略掉(此时是否与修改的行key字段相同没有关系了)。

<fi>支持动态名称。

DATA: scarr_tab TYPE SORTED TABLE OF scarr
               WITH UNIQUE KEY carrid,
      scarr_wa TYPE scarr.
scarr_wa-currcode = 'EUR'.
SELECT * FROM scarr INTO TABLE scarr_tab.
READ TABLE scarr_tab WITH TABLE KEY carrid = 'xxx' TRANSPORTING NO FIELDS.
MODIFY scarr_tab INDEX sy-tabix FROM scarr_wa TRANSPORTING currcode.

修改当前循环行…USING KEY loop_key…

MODIFY itab [USINGKEY loop_key] FROM<wa>

此语句只能用在LOOP AT内表循环语句中,并且此时 USING KEY loop_key 选项也可以省略(其实默认就是省略的),其中 loop_key 是预定义的,不能更改:

LOOP AT scarr_tab INTO scarr_wa.

MODIFY scarr_tab USING KEYloop_keyFROM scarr_wa.

ENDLOOP.

如果<itab>是带有表头的内表,则可以直接使用MODIFY <itab>语句,且此语句只适用于LOOP AT循环语句中

.
  "在循环中可以使用下面简洁方法来修改内表,修改的内表行为当前正被循环的行,即使循环中使用了READ TABLE语句
  "读取了其他内表而导致了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.
WRITE:/ itab2-key, itab2-val .

itab1 index:           1

itab2 index:           1

itab1 index:           2

itab2 index:           1

a          2

b          3

A          0

使用WRITE TO进行修改

WRITE <f> TO <itab> INDEX <idx>.

<itab>必须只能是标准表,且<itab>的行字段都是要是C、N、D、T类型的字段,否则编译出错。

在修改时,<itab>需要使用偏移量的方式来定位需要修改的内容,可以参照

),
  .
LOOP AT code .
  WRITE: / code-c , code-text.
ENDLOOP.

a This is the first line.

b This is the second line. It is NIC.

c This is the third and final line.

DELETE删除指定索引位置上的行

DELETE { {TABLEitab {FROM wa [USING KEY key_name|(name)]} | {WITH TABLE KEY [key_name|(name) COMPONENTS] {comp_name1|(name1)}=dobj1 {comp_name2|(name2)}=dobj2...}} | {itab INDEX idx [USING KEY key_name|(name)]} | {itab [USING KEY loop_key]}
| itab [USING KEY key_name|(name)] [FROM idx1] [TO idx2] [WHERE log_exp|(cond_syntax)]
| ADJACENT DUPLICATES FROM itab [USING KEY key_name|(name)] [COMPARING {comp1 comp2 ...}|{ALL FIELDS}]... }

comp1 comp2 ...
... { comp_name[-sub_comp][{+off(len)}|{->attr}] } | {(name)} ...

删除单行

DELETE<itab> [INDEX<idx>].

如果省略<index>选项,则DELETE <itab>语句只能用在循环语句中。被删除行后面所有行的索引号都将减一。

循环中删除行…USING KEY loop_key…

DELETE itab [USINGKEY loop_key]

此语句只能用在LOOP AT内表循环语句中,并且此时 USING KEY loop_key 选项也可以省略(其实默认就是省略的),其中 loop_key 是预定义的,不能更改:

的行实质上删除的是原索引号为4的行,
的行时会失败,因为此时只有3行数据了
.
WRITE: 'SY-SUBRC =', sy-subrc.
SKIP.
LOOP AT itab INTO line.
  WRITE: / sy-tabix, line-col1, line-col2.
ENDLOOP.

SY-SUBRC =     4

1           1           1

2           3           9

3           5          25

.
    "在循环中可以连续删除
    DELETE itab.
  ENDIF.
ENDLOOP.
LOOP AT itab INTO line.
  WRITE: / sy-tabix, line-col1, line-col2.
ENDLOOP.

1           4          16

2           5          25

的记录
  .
ENDDO.
WRITE:/.
LOOP AT  itab.
  WRITE: / itab.
ENDLOOP.

1

4

2

4

删除多行

DELETE<itab> [FROM<n1>] [TO<n2>] [WHERE<condition>].

只少要指定一个条件。

If at least one line is deleted, the system sets SY-SUBRC to 0, otherwise to 4.

如果没有使用USING KEY选项,或者keyname指定为了primary table key,则选项FROM … TO 只能用在 index tables 类型的内表,在此种情况下,FROM … TO 中指定的行索引值为primary table index 。

如果通过USING KEY选项中keyname设置为了sorted secondary key,则FROM … TO可以应用到Hash内表,在此种情况下,FROM … TO 中指定的行索引值为secondary table index 。

到7的行,且删除条件是col2大于等于25
.
LOOP AT itab INTO line.
  WRITE: / line-col1, line-col2.
ENDLOOP.

1           1

2           4

3           9

4          16

8          64

在循环使用FROM…TO限制行的读取范围

LOOP AT <itab><result> [FROM <n1>] [TO <n2>] <condition>.

<statement block>

ENDLOOP.

循环处理的过程与LOOP在循环中处理行是一样的

在使用FROM或WHERE筛选行时,循环中使用控制关键字 AT (如,AT first)有可能不会工作,原因是触发的行被筛选掉了。

FROM 和 TO 选项限制系统必须读取的行数。WHERE 选项还是会遍历整个内表来选取合适的行,为了提高效率,应该尽可能使用 FROM 和 TO 选项先来限制读取的范围。

.
  WRITE: / sy-tabix, line-col2.
ENDLOOP.

5          25

6          36

7          49

使用字段符号进行访问

当从内表中READ条目或LOOP时,可以使用以下字符符号选项:

... ASSIGNING <FS>

 

字符符号会直接指向对应行所在的内存,与工作区域不同的是,工作区是间接的访问内表,而字符符号是直接访问内表中的行所在的内存。

 

通过字段符号修改字段时,不要对排序表与哈希表的Key字段进修改,否则运行时会出错。另外,在LOOP中使用字段符号时,不能使用SUM,因为SUM只针对工作区域来操作的。

示例参考:使用字段符号

在使用字段符号读取时不需要先将内表行拷贝到工作区域,修改时也不需要先修改工作区的内容,然后再将工作区拷贝到内表中,而是直接对内表行进行操作。使用字段符号操作内表行能能够提高效率。

当使用字段符号指定读取的表行后,系统会注册该字段符号的分配信息,如果指向的表行被删除了,则系统会自动使用字段处于未分配状态,此时IF <fs> IS ASSIGNED表达式为真。

如果在是LOOP中使用删除了字段符号指向的内表行,则不能再对该字段符号进行ASSIGN, UNASSIGN这些操作,但如果不是LOOP循环里是可以的。

.
  .
 .
IF <fs> IS ASSIGNED.
  WRITE '<FS> is assigned!'.
ENDIF.
LOOP AT itab ASSIGNING <fs>.
  WRITE: / <fs>-col1, <fs>-col2.
ENDLOOP.

1           1

2         100

4          16

如果itab本身是一个字段符号的内存,则也可以使用LOOP AT itab into <fs>.

使用表头替换工作区

ABAP 内表 详解

实用的Ranges内表

,
        sign   TYPE c LENGTH 1 VALUE 'I',
        option TYPE c LENGTH 2 VALUE 'eq',
        low    LIKE t001-bukrs,
        high   LIKE t001-bukrs,
      END OF gr_t001.

可以通过Ranges内表的IN表达式来巧妙的判断某个记录是否已在该内表中存在,这好比Java中的集合判断某个值是否在集合中存在一样,非常实用

RANGES: s_ebeln1 FOR ekko-ebeln.

s_ebeln1-sign = 'I'.
  s_ebeln1-option = 'EQ'.
  s_ebeln1-low = 'xxxxxxxxxx'.
  APPEND s_ebeln1."开始时一定要加入一个条件,否则 th_alv-ebeln in s_ebeln1恒为真

CLEAR: s_ebeln1.
  LOOP AT th_alv WHERE checkbox NE space.
    "巧妙使用s_ebeln1不只是在OPENSQL中使用In,只要是在逻辑表达式中都能使用
    IF NOT th_alv-ebeln IN s_ebeln1.
      s_ebeln1-sign = 'I'.
      s_ebeln1-option = 'EQ'.
      s_ebeln1-low = th_alv-ebeln.
      APPEND s_ebeln1."如果不存在,则增加
    ENDIF.
  ENDLOOP.