ABAP 内表 详解

老式的内表类型定义... 214

基于基本类型内表类型... 214

基于结构体类型内表类型... 215

老式的内表对象创建... 215

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

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

两种内表对象等效创建... 215

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

DATAWITH HEADER LINE. 217

新式内表的定义... 217

使用第二索引... 221

INDEX/ANY TABLE通用型内表... 222

内表整体操作... 222

内表间赋值... 222

比较内表... 222

排序内表SORT….. 223

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

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

稳定排序STABLE. 227

DESCRIBETABLE获取内表属性... 227

获取内表数据行数 Lines()227

内表行操作... 227

单行操作... 227

多行操作... 228

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

INSERT向表中插入行... 228

插入一行... 228

插入多行FROM…TO.. 229

COLLECT合并... 229

READ 读取行... 230

指定搜索关键字段... 231

使用表关键字段进行读取... 231

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

以行首字段搜索... 233

USING KEY.. 233

<result>指定额外处理选项... 233

指定工作区... 233

COMPARING比较读取的单行内容... 234

TRANSPORTING读取一行的部分字段... 234

使用字段符号... 235

MODIFY 修改行... 236

修改单条记录(TABLE KEY... 236

修改多条记录(WHERE... 237

DELETE 删除行... 237

循环中插入或删除行... 237

删除单行(TABLE KEY... 238

删除多行(WHERE... 238

删除邻近重复行(ADJACENT DUPLICATE... 239

LOOP在循环中处理行... 240

SUM.. 240

AT. 241

适用索引表的行操作... 246

APPEND 附加行... 246

附加单行... 246

附加多行FROM… TO.. 247

以排序方式附加... 248

APPEND …SORTED BY….. 248

USING KEY. 249

INSERT插入到指定的索引位置... 250

插入单行... 250

插入多行FROM…TO.. 251

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

在索引表中进行二分搜索... 252

在内表中搜索字符串... 253

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

修改单行... 254

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

使用WRITE TO进行修改... 255

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

删除单行... 256

循环中删除行…USING KEY loop_key….. 256

删除多行... 258

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

使用字段符号进行访问... 259

使用表头替换工作区... 260

实用的Ranges内表

内表

老式的内表类型定义

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

 

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

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

基于基本类型内表类型

"如果去掉了 OCCURS 则表示是普通类型而不是内表类型
TYPES vector TYPE i OCCURS 10.
"如果要带隐藏表头则一定要加上WITH HEADER LINE否则默认没有而且只能在声明内表变量时加而不能在上面定义内表类型时加
DATA vector TYPE vector WITH HEADER LINE.

vector = 1.
APPEND vector.

 

上面的TYPES与下面语句等效

TYPES vector TYPE STANDARD TABLE OF i
       
WITH NON-UNIQUE DEFAULT KEY
       
INITIAL SIZE 10.

 

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

 

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

 

下面这样也可以

TYPES vector TYPE i.
DATA vector TYPE vector OCCURS 0 WITH HEADER LINE.
vector
= 1.
APPEND vector.

基于结构体类型内表类型

"由于没有加 occurs 选项所以定义的是一结构类型
TYPES: BEGIN OF line,
         column1
TYPE i,

         column2
TYPE i,
         column3
TYPE i,
      
END OF line.
"
定义一内表类型而不是普通类型
TYPES itab TYPE line OCCURS 10.

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

 

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

TYPES: BEGIN OF itab OCCURS 10,
         column1
TYPE i,
         column2
TYPE i,
         column3
TYPE i,
      
END OF itab.

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

老式的内表对象创建

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

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

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

 

TYPES type TYPE i OCCURS 10.
DATA vector TYPE type WITH HEADER LINE.

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

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

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

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

两种内表对象等效创建

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

TYPES vector_type TYPE i OCCURS 10.
DATA vector TYPE vector_type WITH HEADER LINE
.

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

DATA vector TYPE i OCCURS 10 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

DATA: BEGIN OF itab OCCURS 10,
         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 ...才会):

  DATA: BEGIN OF line,
          col1
TYPE i
,
          col2
TYPE i
,
       
END OF
line.
 
DATA itab LIKE line OCCURS 10 ."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 t1  TYPE i  OCCURS 10 .
TYPES t2 TYPE  t1  OCCURS 10
.

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.

"下面去掉 WITH HEADER LINE就可以了
DATA d2 TYPE  t1  OCCURS 10 .
"
与上面语句等效
*DATA d2 TYPE  t2 .

"现向内表d2中加数据时,要经过以下步骤
DATA w_d1 LIKE LINE OF d2."d2内表的行类型,还是一个内表,以下还需进一步定义
DATA w_d1_2 LIKE LINE OF w_d1."现在w_d1_2是一个结构对象了,该结构没有字段
w_d1_2 =
1.

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.

DATAWITH HEADER LINE

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

TYPES: BEGIN OF line,
         column1
TYPE i
,
         column2
TYPE i
,
         column3
TYPE i
,
      
END OF line
.
TYPES itab TYPE line OCCURS 10
.
"
定义内表对象,但不带表头
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 通用类型只用用在只能用在字段特号与形式参数中

image173

tabkeys

...[WITH[UNIQUE|NON-UNIQUE]{{KEY[primary_key[ALIAS key_name]COMPONENTS] comp1 comp2 ...}|{DEFAULT KEY}}]  "主键索引
[
WITH{UNIQUE HASHED}|{UNIQUE SORTED}|{NON-UNIQUE SORTED} KEY key_name COMPONENTS comp1 comp2 ... ] ... "第二索引,最多支持15个第二索引

[{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 ]…"第二索引,最多支持15个第二索引

] 

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

 

 

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

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

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

 

tabkind取值如下

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

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

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

 

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

image174

image175

对于索引类型的内表,当一个行操作语句执行结束后,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 LINETABLE_LINE:将表的整行作为Key,则可以使用TABLE_LINE

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

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

 

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

 

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

 

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

 

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

 

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

DATA: BEGIN OF line0 OCCURS 0,
     
i TYPE i ,
     
c(1),
     
END OF line0.
DATA: BEGIN OF line1,
     
i TYPE i ,
     
c(1),
      itab
LIKE line0[],
     
END OF line1.
DATA: BEGIN OF line2 OCCURS 0,
       
i TYPE i ,
       
c TYPE string,
       
line LIKE line1,
     
END OF line2.

line0
-i = 1.
line0
-c = 'a'.
APPEND line0 .
line0
-i = 2.
line0
-c = 'b'.
APPEND line0 .

line1
-i = 3.
line1
-c = 'c'.
line1
-itab = line0[].

line2
-i = 4.
line2
-c = 'd'.
line2
-line = line1.
APPEND line2.
LOOP AT  line2 .
 
WRITE: / line2-i , line2-c.
ENDLOOP.

CLEAR: line1.
line1
-i = 32.
line1
-c = 'c'.
CLEAR:line2.
line2
-i = 5.
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明确指定关键字段时,如果内表行包含结构组件,还可以指定到该结构组件的某个元素作为关键字段:

TYPES: BEGIN OF line0,
     
i TYPE i ,
     
c(1),
     
END OF line0.
TYPES: BEGIN OF line1,
     
i TYPE i ,
     
c(1),
      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 itabAPPEND语句中通过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),一般性类型可以用于类型定义中,但不能用于声明一个内表对象,因为它并没有指明任何明确的表类型,因而系统无法确定对其操作方式。一般性类型还可以用于指明字段符号和接口参数的类型,其实际类型可能在运行期内才能够确定。

image176

内表整体操作

内表间赋值

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

不推荐:

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

 

image177

image178

 

 

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.

内表行操作

单行操作

image179

多行操作

image180

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

在该节中列出的操作适用所有类型的内表。如果你在操作之前知道内表的类型,请使用合适的操作,比如,使用 APPEND…TO 语句填充索引内表,使用 INSERT…INTO TABLE 来填充Hash表或通用性类型(ANY TABLEINDEX 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倍。

DATA: BEGIN OF line,
col1
TYPE i
,
col2
TYPE i
,
col3
TYPE c
,
END OF line
.
DATA: itab LIKE STANDARD TABLE OF line
,
      jtab
LIKE SORTED TABLE OF line

           
WITH NON-UNIQUE KEY col1 col2.
DO 2 TIMES
.
 
line-col1 = sy-index. line-col2 = sy-index ** 2.line-col3 = 'a'
.
 
APPEND line TO
itab.
 
line-col1 = sy-index. line-col2 = sy-index ** 3.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>必须是扁平结构,所有其他非关键字段的字段必须是数字类型(IFP):

DATA: BEGIN OF line,
col1
TYPE c
,
col2
TYPE i
,
col3
TYPE c
,
END OF line
.
DATA: itab like STANDARD TABLE OF line

       
WITH HEADER LINE WITH NON-UNIQUE key col1.
itab-col1 =
'a'
.
itab-col2 =
1
.
itab-col3 =
'b'
.
APPEND
itab.
itab-col1 =
'a'
.
itab-col2 =
2
.
itab-col3 =
'c'
.
"
编译出错:非关键字段必须是 I P F 数字类型
*COLLECT itab INTO itab.

 

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

 

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

 

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

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

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

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

 

DATA: BEGIN OF line,
col1(3) TYPE c
,
col2(
2) TYPE
n,
col3
TYPE i
,
END OF line
.
DATA itab LIKE SORTED TABLE OF line

     
WITH NON-UNIQUE KEY col1 col2.
line-col1 = 'abc'. line-col2 = '12'. line-col3 = 3
.
COLLECT line INTO
itab.
WRITE
/ sy-tabix.
line-col1 = 'def'. line-col2 = '34'. line-col3 = 5
.
COLLECT line INTO
itab.
WRITE
/ sy-tabix.
line-col1 = 'abc'. line-col2 = '12'. line-col3 = 7
.
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 KEYWITH [TABLE] KEY key_name选项明确的指定通过UNIQUE SORTEDNON-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 ,则不同的类型的内表读取的方式不一样:

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

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

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

 

DATA: BEGIN OF line,
         col1
TYPE c,
         col2
TYPE p DECIMALS 5,
     
END OF line.
DATA itab LIKE line OCCURS 10 WITH HEADER LINE.
DO 5 TIMES.
 
line-col1 = sy-indexline-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是一个工作区,并且整个内表的行的所有字段都会作为搜索条件。注:一定是整行,而不是内表本身那些关键字段所构成的字段,也就是说与内表本身关键字段没有任何关系,请看下面示例:

DATA: BEGIN OF line,
         col1
TYPE c
,
         col2
TYPE
n,
         col3
TYPE i
,
     
END OF line
,
      line2
LIKE line
.
DATA: itab LIKE STANDARD TABLE OF line WITH HEADER LINE WITH KEY
col1 col2 .
line-col1 = '1'
.
line-col2 = '1'
.
line-col3 = 10
.
APPEND line TO
itab.
line-col1 = '2'
.
line-col2 = '2'
.
line-col3 = 20
.
APPEND line TO
itab.
CLEAR: line
.
line-col1 = '1'
.
line-col2 = '1'
.
"
注:这里不能省略下面语句,否则查找不到
line-col3 = 10.
READ TABLE itab INTO line2 WITH KEY = line
.
WRITE
: / sy-subrc, line2-col1.

"
如果行类型本身就是基本类型时
DATA: itab2 TYPE STANDARD TABLE OF i WITH HEADER LINE with KEY TABLE_LINE.
itab2 =
2
.
append
itab2.
itab2 =
1
.
append
itab2.
READ TABLE itab2 WITH KEY = 2
.
WRITE
: / sy-subrc, itab2.

 

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

 

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

以行首字段搜索

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

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

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

DATA: BEGIN OF line,
        
i TYPE i,
        
c TYPE c,
     
END OF line.
DATA itab LIKE line OCCURS 10.
line-i = 10.
line-c = 'a'.
append line to itab.
CLEAR: line
.
"以第一个字段为key
READ TABLE itab INTO line WITH KEY 10.
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如果系统找到条目,则无论比较结果如何,都将其读入目标区域

DATA: BEGIN OF line,
col1
TYPE i
,
col2
TYPE i
,
END OF line
.
DATA itab LIKE HASHED TABLE OF line WITH UNIQUE KEY
col1.
DO 3 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
INSERT line INTO TABLE
itab.
ENDDO
.
line-col1 = 2. line-col2 = 3
.
READ TABLE itab FROM line INTO line COMPARING col2.

WRITE: 'SY-SUBRC =', sy-subrc.
WRITE: / line-col1, line
-col2.

SY-SUBRC =     2

         2           4

 

DATA: BEGIN OF line,
         col1
TYPE i,
         col2
TYPE i,
         col3
TYPE i,
     
END OF line.
DATA itab LIKE line OCCURS 10.
DO 10 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
line-col3 = sy-index ** 3.
 
APPEND line TO itab.
ENDDO.
CLEAR: line.
line-col1 = 2. line-col2 = 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>,则会忽略掉。

DATA: BEGIN OF line,
col1
TYPE i
,
col2
TYPE i
,
END OF line
.
DATA itab LIKE SORTED TABLE OF line WITH UNIQUE KEY
col1.
DO 4 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
INSERT line INTO TABLE
itab.
ENDDO
.
CLEAR line
.
READ TABLE itab WITH TABLE KEY col1 = 3INTO 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

 

DATA: BEGIN OF line,
col1
TYPE i
,
col2
TYPE i
,
END OF line
.
DATA itab LIKE SORTED TABLE OF line WITH UNIQUE KEY
col1.
DO 4 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
INSERT line INTO TABLE
itab.
ENDDO
.
READ TABLE itab WITH KEY col2 = 16 TRANSPORTING NO FIELDS
.
WRITE: 'SY-SUBRC ='
, sy-subrc,
/
'SY-TABIX ='
, sy-tabix.

SY-SUBRC =     0

SY-TABIX =          4

使用字段符号

image181

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

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

 

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

 

DATA: BEGIN OF line,
col1
TYPE i
,
col2
TYPE i
,
END OF line
.
DATA itab LIKE HASHED TABLE OF line WITH UNIQUE KEY
col1.
FIELD-SYMBOLS <fs> LIKE LINE OF
itab.
DO 4 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
INSERT line INTO TABLE
itab.
ENDDO
.
READ TABLE itab WITH TABLE KEY col1 = 2 ASSIGNING
<fs>.
<fs>-col2 =
100
.
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 [
TRANSPORTING comp1 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 为空,则运行时会忽略。

 

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE HASHED TABLE OF line WITH UNIQUE KEY col1.
DO 4 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
INSERT line INTO TABLE itab.
ENDDO.
line-col1 = 2. line-col2 = 100.
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-SUBRC0,否则为4

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE HASHED TABLE OF line WITH UNIQUE KEY col1.
DO 4 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
INSERT line INTO TABLE itab.
ENDDO.
line-col2 = 100.
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 { {TABLE itab {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了;但如果是删除的是当前遍历的行,则下次删除还是继续接着删除下一行数据,并且删除后下次循环的索引还是与上次一样(所以能连续删除,不会隔行删除) 

循环中插入行请参见这里

循环中删除行请参见这里

 

下面也能删除所有行:

LOOP AT itab_person FROM 1 to 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 内表,且满足条件的有多条件数据时,只会删除第一条

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE HASHED TABLE OF line WITH UNIQUE KEY col1.
DO 4 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
INSERT line INTO TABLE itab.
ENDDO.
line-col1 = 1.
DELETE TABLE itab: FROM line,
WITH TABLE KEY col1 = 3.
LOOP AT itab INTO line.
 
WRITE: / line-col1, line-col2.
ENDLOOP.

         2           4

         4          16

删除多行(WHERE

DELETE<itab>WHERE<cond>.

 

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

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE HASHED TABLE OF line WITH UNIQUE KEY col1.
DO 4 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
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>),才能删除所有重复数据。

 

DATA: BEGIN OF line,
        col1
TYPE i
,
        col2
TYPE c
,
     
END OF line
.
DATA itab LIKE line OCCURS 10
.
line-col1 = 1. line-col2 = 'A'. APPEND line TO
itab.
line-col1 = 1. line-col2 = 'A'. APPEND line TO
itab.
line-col1 = 1. line-col2 = 'B'. APPEND line TO
itab.
line-col1 = 2. line-col2 = 'B'. APPEND line TO
itab.
line-col1 = 3. line-col2 = 'B'. APPEND line TO
itab.
line-col1 = 4. line-col2 = 'B'. APPEND line TO
itab.
line-col1 = 5. line-col2 = 'A'. APPEND line TO
itab.
LOOP AT itab INTO line
.
 
WRITE: / line-col1, line
-col2.
ENDLOOP
.
"
所有字段相同时才算重复
DELETE ADJACENT DUPLICATES FROM itab COMPARING ALL FIELDS.
SKIP TO LINE 3
.
LOOP AT itab INTO line
.
 
WRITE: /14 line-col1, line
-col2.
ENDLOOP
.
"
指定字段重复时
DELETE ADJACENT DUPLICATES FROM itab COMPARING col1.
SKIP TO LINE 3
.
LOOP AT itab INTO line
.
 
WRITE: /28 line-col1, line
-col2.
ENDLOOP
.
"
根据表关键字段col2来判断是否重复
DELETE ADJACENT DUPLICATES FROM itab.
SKIP TO LINE 3
.
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 AT itab {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,如:

DATA: hash TYPE HASHED TABLE OF i WITH HEADER LINE WITH UNIQUE KEY TABLE_LINE.
INSERT 4 INTO TABLE
hash.
INSERT 2 INTO TABLE
hash.
INSERT 3 INTO TABLE
hash.
INSERT 1 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 语句。

DATA: BEGIN OF line,
         col1
TYPE i
,
         col2
TYPE i
,
     
END OF line
.
DATA itab LIKE line OCCURS 10
.
DO 3 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
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 NEWAT END OF(另一好处是在循环内表时可以使用Where条件语句)(注:使用这种只需要按照分组的顺序排序即可,如要分成bukrsbukrs anlkl两组时,需要按照BY bukrs anlkl排序,而不能是BYanlkl bukrs):

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

"下面假设按bukrsbukrs 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 .不是分组中最末行

  "这里还是要清一下,以防该代码直接写在报表程序的事件里,而不是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.

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

 

 

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

 

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

 

DATA: BEGIN OF line,
     
"C2C3组件名声明的顺序一定要与在AT...... ENDAT块中使用的次序一致,即这里不能将C3声明在C2之前,且不能在C2C3之间插入其他字段的声明
      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...... ENDAT语句中的字段不一定要是关键字段
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

 

 

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

image182

另外,其实这个统计与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 NEWAT 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>

 

 

DATA: BEGIN OF line1,
col1
(3) TYPE c,
col2
(2) TYPE n,
col3
TYPE i,
END OF line1,
tab1
LIKE TABLE OF line1.

DATA: BEGIN OF line2,
field1
(1) TYPE c,
field2
LIKE tab1,"嵌套内表
END OF line2,
tab2
LIKE TABLE OF line2.

line1
-col1 = 'abc'. line1-col2 = '12'. line1-col3 = 3.
APPEND line1 TO tab1.
line1
-col1 = 'def'. line1-col2 = '34'. line1-col3 = 5.
APPEND line1 TO tab1.
line2
-field1 = 'A'. line2-field2 = tab1.
APPEND line2 TO tab2.

REFRESH tab1.
line1
-col1 = 'ghi'. line1-col2 = '56'. line1-col3 = 7.
APPEND line1 TO tab1.
line1
-col1 = 'jkl'. line1-col2 = '78'. line1-col3 = 9.
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>只能是索引类型的内表(索引表、标准表)

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

DATA: BEGIN OF line,
col1
TYPE c,
col2
TYPE i,
END OF line.
DATA: itab LIKE TABLE OF line,
jtab
LIKE itab.
DO 3 TIMES.
 
line-col1 = sy-index. line-col2 = sy-index ** 2.
 
APPEND line TO itab.
 
line-col1 = sy-index. line-col2 = sy-index ** 3.
 
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 语句对表格进行排序。

DATA: BEGIN OF itab OCCURS 2,
         column1
TYPE i
,
         column2
TYPE i
,
         column3
TYPE i
,
      
END OF
itab.
itab-column1 =
1. itab-column2 = 2. itab-column3 = 3
.
APPEND itab SORTED BY
column2.
itab-column1 =
4. itab-column2 = 5. itab-column3 = 6
.
APPEND itab SORTED BY
column2.
itab-column1 =
7. itab-column2 = 8. itab-column3 = 9
.
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>进行比较(采用降序比较)找到插入位置,将超过nn为内表定义语句中的INITIAL SIZE 选项中所指定的n)行之外的最后一行删除,只保留前n条记录。

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

DATA: BEGIN OF line,
  col1
TYPE i,
  col2
TYPE i,
END OF line.
"
这里的2对后面的APPEND语句产生影响:保留前2名的记录
DATA itab LIKE TABLE OF line INITIAL SIZE 2.
line-col1 = 1. line-col2 = 2.
APPEND line TO itab SORTED BY col2 .
LOOP AT itab INTO line.
 
WRITE: / line-col2.
ENDLOOP
.
SKIP.
line-col1 = 3. line-col2 = 4.
APPEND line TO itab SORTED BY col2.
LOOP AT itab INTO line.
 
WRITE: / line-col2.
ENDLOOP
.
SKIP.
line-col1 = 5. line-col2 = 6.
APPEND line TO itab SORTED BY col2.
LOOP AT itab INTO line.
 
WRITE: / line-col2.
ENDLOOP.

image183

USING KEY 

 

TYPES:BEGIN OF tab_type ,
    a
TYPE i,
    b
TYPE i,
   
c TYPE i,
    d
TYPE i,
    e
TYPE i,
 
END OF  tab_type .

DATA itab
     
TYPE STANDARD TABLE  OF
tab_type
     
WITH NON-UNIQUE KEY
primary_key COMPONENTS a
     
WITH UNIQUE HASHED KEY
hash_key COMPONENTS b
     
WITH NON-UNIQUE SORTED KEY sort_key COMPONENTS c

     
WITH HEADER LINE.

DATA itab2 LIKE itab[] WITH HEADER LINE.

itab
-a = 3.itab-b = 5.itab-c = 5.itab-d = 6.itab-e = 1.
APPEND itab.
itab
-a = 6.itab-b = 8.itab-c = 4.itab-d = 1.itab-e = 2.
APPEND itab.
itab
-a = 1.itab-b = 3.itab-c = 2.itab-d = 4.itab-e = 3.
APPEND itab.
itab
-a = 4.itab-b = 7.itab-c = 6.itab-d = 1.itab-e = 4.
APPEND itab.

APPEND LINES OF itab FROM 2 to 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 排序表中插入重复值,另外向排序表中插入值时不能违反排序表的默认排序规则,否则运行时出错。

 

 

循环中插入或删除行

DATA: BEGIN OF line,
         col1
TYPE i
,
         col2
TYPE i
,
     
END OF line
.
DATA itab LIKE line OCCURS 10
.
DO 2 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
APPEND line TO
itab.
ENDDO
.
"
在循环中插入行后,下次循环的行还是当前行的后行,循环连续的,但索引号增1
LOOP AT itab INTO line.
 
WRITE
: / sy-tabix.
 
line-col1 = 3 * sy-tabix. line-col2 = 5
* sy-tabix.
 
INSERT line INTO itab."
未指定INDEX选项,所以在当前行前插入
 
WRITE: sy-tabix.
ENDLOOP
.
LOOP AT itab INTO line
.
 
WRITE: / sy-tabix, line-col1, line
-col2.
ENDLOOP
.
SKIP
.
LOOP AT itab INTO line
.
  "
会删除所有索引大于1的数据行,删除后下次循环的索引还是与上次相同
 
IF sy-tabix > 1.
   
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>只能是索引类型的内表(索引表、标准表)。

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

DATA: BEGIN OF line,
col1
TYPE i
,
col2
TYPE i
,
END OF line
.
DATA: itab LIKE TABLE OF line
,
jtab
LIKE
itab.
DO 3 TIMES
.
 
line-col1 = sy-index. line-col2 = sy-index ** 2
.
 
APPEND line TO
itab.
 
line-col1 = sy-index. line-col2 = sy-index ** 3
.
 
APPEND line TO
jtab.
ENDDO
.
INSERT lines of itab FROM 2 TO 3 INTO jtab INDEX 1.

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-SUBRC0,且SY-TABIX存储当前找到的数据行索引,如果未找到,则SY-SUBRC为非0

 

DATA: BEGIN OF line,
  col1
TYPE i
,
  col2
TYPE i
,
END OF line
.
DATA itab LIKE SORTED TABLE OF line WITH UNIQUE KEY
col1.
FIELD-SYMBOLS <fs> LIKE LINE OF
itab.
DO 20 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = 2 * sy-index
.
 
APPEND line TO
itab.
ENDDO
.
READ TABLE itab INDEX 7 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表进行排序,而且具有排序效果(这个比较意外,有点像JavaTreemap集合了):

TYPES: BEGIN OF line,
   
i TYPE i
,
 
END OF line
.
DATA: itab TYPE HASHED TABLE OF line WITH HEADER LINE WITH UNIQUE KEY i
.
itab-
i = 1
.
INSERT  itab INTO TABLE
itab.
itab-
i = 2
.
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

 

 

DATA: BEGIN OF line,
col1
TYPE i
,
col2
TYPE i
,
END OF line
.
DATA itab LIKE STANDARD TABLE OF line
.
DO 4 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
APPEND line TO
itab.
ENDDO
.
"
注:二分搜索时只能是按升序排序
*SORT itab BY col2 DESCENDING.
SORT itab BY col2."默认就是升序
READ TABLE itab WITH KEY col2 = 16 INTO line BINARY SEARCH
.
WRITE: 'SY-SUBRC ='
, sy-subrc.

SY-SUBRC =     0

在内表中搜索字符串

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

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

 

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

 

DATA: BEGIN OF line,
 
index(2) TYPE
n,
 
text(10) TYPE c
,
END OF line
.
DATA itab LIKE SORTED TABLE OF line WITH UNIQUE KEY index
.
DATA num(2) TYPE
n.
DO 3 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 [
TRANSPORTING comp1 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循环语句中

 

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 = 'a'.
itab1
-val = 1.
APPEND itab1.
itab1
-key = 'b'.
itab1
-val = 2.
APPEND itab1.
itab2
-key = 'A'.
itab2
-val = 0.
APPEND itab2.
LOOP AT itab1.
 
WRITE: / 'itab1 index: ' , sy-tabix.
 
READ TABLE itab2 INDEX 1 TRANSPORTING NO FIELDS.
 
WRITE: / 'itab2 index: ', sy-tabix.
  itab1
-val = itab1-val + 1.
 
"在循环中可以使用下面简洁方法来修改内表,修改的内表行为当前正被循环的行,即使循环中使用了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>的行字段都是要是CNDT类型的字段,否则编译出错。

 

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

 

DATA: BEGIN OF line,
     
c
,
     
text(72
),
 
END OF line
.
DATA code LIKE  TABLE OF line WITH HEADER LINE WITH NON-UNIQUE KEY c
.
code-c = 'a'
.
code-text = 'This is the first line.'
.
APPEND code
.
code-c = 'b'
.
code-text = 'This is the second line. It is ugly.'
.
APPEND code
.
code-c = 'c'
.
code-text = 'This is the third and final line.'
.
APPEND code
.
"
偏移量是指在整个行所有字段组成的字符串的偏移量,这里包括了前面 c 字段
WRITE ' NIC.' TO code+31 INDEX 2.
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 { {TABLE itab {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 是预定义的,不能更改:

 

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE SORTED TABLE OF line WITH UNIQUE KEY col1.
DO 5 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
APPEND line TO itab.
ENDDO.
"删除索引号为3的行实质上删除的是原索引号为4的行,
"删除索引号为4的行时会失败,因为此时只有3行数据了
DELETE itab INDEX: 2, 3, 4.
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

 

 

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE TABLE OF line.
DO 5 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
APPEND line TO itab.
ENDDO.
LOOP AT itab INTO line.
 
IF line-col1 < 4
.
    "在循环中可以连续删除
    DELETE itab
.
 
ENDIF.
ENDLOOP.
LOOP AT itab INTO line.
 
WRITE: / sy-tabix, line-col1, line-col2.
ENDLOOP.

         1           4          16

         2           5          25

 

 

 

DATA: itab TYPE TABLE OF i WITH HEADER LINE.
APPEND 1 TO itab.
APPEND 2 TO itab.
APPEND 3 TO itab.
APPEND 4 TO itab.
APPEND 5 TO itab.

LOOP AT itab."循环内表本身可以循环删除所有,但下面的条件是只删除2、3、5的记录
 
IF itab = 2 OR itab = 3 OR itab = 5.

  
 DELETE itabindex sy-tabix."index sy-tabix可以省
  ENDIF.
ENDLOOP.
LOOP AT  itab.
 
WRITE: / itab.
ENDLOOP.
FREE itab.

APPEND 1 TO itab.
APPEND 2 TO itab.
APPEND 3 TO itab.
APPEND 4 TO itab.
APPEND 5 TO itab.
DO 5 TIMES."通过DO xx TIMES方式不能循环删除所有
 
DELETE itab INDEX sy-index.
ENDDO.
WRITE:/.
LOOP AT  itab.
 
WRITE: / itab.
ENDLOOP.

FREE itab.

APPEND 1 TO itab.
APPEND 2 TO itab.
APPEND 3 TO itab.
APPEND 4 TO itab.
APPEND 5 TO itab.
DO 5 TIMES."这样也可以删除所有行
 
DELETE itab INDEX 1.
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 

 

 

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE TABLE OF line.
DO 8 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
APPEND line TO itab.
ENDDO.
"删除索引为37的行,且删除条件是col2大于等于25
DELETE itab FROM 3 TO 7 WHERE 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在循环中处理行是一样的

 

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

 

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

DATA: BEGIN OF line,
col1
TYPE i,
col2
TYPE i,
END OF line.
DATA itab LIKE SORTED TABLE OF line WITH UNIQUE KEY TABLE
LINE.
DO 10 TIMES.
 
line-col1 = sy-index.
 
line-col2 = sy-index ** 2.
 
APPEND line TO itab.
ENDDO.
LOOP AT itab INTO line FROM 4 TO 8 WHERE col2 > 16 and col2 < 64.
 
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循环里是可以的。

 

DATA: BEGIN OF line,
  col1
TYPE i
,
  col2
TYPE i
,
END OF line
.
DATA itab LIKE SORTED TABLE OF line WITH UNIQUE KEY
col1.
FIELD-SYMBOLS <fs> LIKE LINE OF
itab.
DO 4 TIMES
.
 
line-col1 = sy-index
.
 
line-col2 = sy-index ** 2
.
 
APPEND line TO
itab.
ENDDO
.
READ TABLE itab WITH TABLE KEY col1 = 2 ASSIGNING <fs>
.
<fs>-col2 =
100
.
READ TABLE itab WITH TABLE KEY col1 = 3 ASSIGNING <fs>
.
"<fs>
指向的行被删除,则IS ASSIGNED逻辑表达式将为假
DELETE itab INDEX 3.
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>.

使用表头替换工作区

image184

实用的Ranges内表

 

DATA: BEGIN OF gr_t001 OCCURS 0,
     
  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
.

posted @ 2015-02-15 21:25  江正军  阅读(57923)  评论(0编辑  收藏  举报