标签:
COLLECT [<wa>INTO] <itab> 将具有相同关键字段值的行中同名的数字字段的值累计到一条记录上,只有非表关键字段被累加;当在内表中找不到指定的被累加行时,COLLECT语句的功能与APPEND语句是一样的,即将一个工作区的内容附加到itab内表中。使用COLLECT操作的内表有一个限制,即该的行结构中,除了表键字段以外的所有字段都必须是数字型(i、p、f)
INSERT <wa> INTO TABLE <itab>."单条插入
INSERT LINES OF <itab1> [FROM <n1>] [TO <n2>] INTO TABLE<itab2>"批量插入
向UNIQUE 的排序表或哈希表插入重复的数据时,不会抛异常,但数据不会被插入进去,这与APPEND是不一样的
Hash内表的KEY设置只能是开头前部分定义的连续的组件字段,不能只将中间或先后几个字段设置为KEY,否则在查找时会出问题,数据无法查到
"只要根据关键字或索引在内表中读取到相应数据,不管该数据行是否与COMPARING 指定的字段相符,都会存储到工作区
READ TABLE <itab> WITH KEY {<k1> = <f1> ... <kn> = <fn>... [BINARY SEARCH] }
INTO <wa> [COMPARING <f1><f2> ...|ALL FIELDS]
[TRANSPORTING <f1><f2> ...|ALL FIELDS|NO FIELDS]
READ TABLE <itab> FROM <wa>…以表关键字为查找条件,条件值来自<wa>
COMPARING:系统根据<k1>...<kn>(关键字段)读取指定的单行与工作区<wa>中的相应组件进行比较。
如果系统找根据指定<k1>...<kn>找到了对应的条目,且进行比较的字段内容相同,则将 SY-SUBRC 设置为0,如果进行比较的字段内容不同,则返回值 2;如果系统根据<k1>...<kn>找不到条目,则包含 4。如果系统找到条目,则无论比较结果如何,都将其读入wa中
MODIFY TABLE <itab> FROM <wa> [TRANSPORTING <f1> <f2> ...] "修改单条(MODIFY TABLE <itab> 一般用在循环中修改哈希表,且itab内表带表头)。这里的<wa>扮演双重身份,不仅指定了要修改的行(条件),还包括要修改的新的值。系统以整个表的所有关键字段来搜索要修改的行;USING KEY:如果未使用此选项,则会使用默认的主键primary table key来修改相应的行;如果找到要修改的行,则将<wa>中所有非关键字段的内容拷贝到对应的数据行中对应的字段上;如果有多行满足条件时只修改第一条
MODIFY <itab> FROM <wa> TRANSPORTING <f1><f2>...WHERE<cond>"修改多条
DELETE TABLE <itab> FROM <wa> "删除单条。多条时,只会删除第一条。条件为所有表关键字段,值来自<wa>
DELETE TABLE <itab> WITH TABLE KEY <k1> = <f1> ..."删除单条。多条时只会删除第一条,条件为所有表关键字
DELETE itab WHERE ( col2 > 1 ) AND ( col1 < 4 ) "删除多行
DELETE ADJACENT DUPLICATES FROM <itab> [COMPARING<f1><f2> ... | ALL FIELDS]
注,在未使用COMPARING 选项时,要删除重复数据之前,一定要按照内表关键字声明的顺序来进行排序,才能删除重复数据,否则不会删除掉;如果指定了COMPARING 选项,则需要根据指定的比较字段顺序进行排序(如COMPARING <F1><F2>时,则需要sort by <F1><F2>,而不能是sort by <F2><F1>),才能删除所有重复数据 [??d?eis?nt] 邻近的 [?dju:plikit] 完全一样的,复制的
APPEND <wa> TO <itab>
APPEND LINES OF <itab1> [FROM<n1>] [TO<n2>] TO<itab2>
INSERT <wa> INTO <itab> INDEX <idx>"如果不使用 INDEX 选项,则将新的行插入到当前行的前面,一般在Loop中可省略INDEX 选项
INSERT LINES OF <itab1> [FROM <n1>] [TO <n2>] INTO <itab2> INDEX <idx>
APPEND/INSERT…INDEX 操作不能用于Hash表
APPEND/INSERT…INDEX用于排序表时条件:附加/插入时一定要按照Key的升序来附加;如果是Unique排序表,则不能附加/插入重附的数据,这与INSERT…INTO TABLE是不一样的
READ TABLE <itab> INDEX <idx>
INTO <wa> [COMPARING <f1><f2> ...|ALL FIELDS]
[TRANSPORTING <f1><f2> ...|ALL FIELDS|NO FIELDS]
| ASSIGNING <fs>
MODIFY <itab> [INDEX <idx> ] FROM <wa> [TRANSPORTING <f1> <f2> ... ] "如果没有 INDEX 选项,只能在循环中使用该语句
DELETE <itab> [INDEX<idx>] "删除单条。如果省略<index>选项,则DELETE <itab>语句只能用在循环语句中
DELETE<itab> [FROM<n1>] [TO<n2>] WHERE<condition> "删除多条
LOOP AT itab {INTO wa}|{ASSIGNING <fs> [CASTING]}|{TRANSPORTING NO FILDS}
[[USING KEY key_name|(name)] [FROM idx1] [TO idx2] [WHERE log_exp|(cond_syntax)]].
ENDLOOP.
FROM … TO: 只适用于标准表与排序表 WHERE … : 适用于所有类型的内表
如果没有通过USING KEY选项的key_name,则循环读取的顺序与表的类型相关:
l 标准表与排序表:会按照primary table index索引的顺序一条条的循环,且在循环里SY-TABIX为当前正在处理行的索引号
l 哈希表:由于表没有排序,所以按照插入的顺序来循环处理,注,此时SY-TABIX 总是0
可以在循环内表时增加与删除当前行:If you insert or delete lines in the statement block of a LOOP , this will have the following effects:
如果在 AT - ENDAT 块中使用 SUM,则系统计算当前行组中所有行的数字字段之和并将其写入工作区域中相应的字段中
<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.
一旦进入到 AT...<f1>...ENDAT 块中时,当前工作区(或表头)中的从<f1>往后,但不包括<f1>(按照在结构中声明的次序)所有字段的字符类型字段会以星号(*)号来填充,而数字字设置为初始值(注:在测试过程中发现String类型不会使用*来填充,而是设置成empty String,所以只有固定长度类型的非数字基本类型才设置为*)。如果在 AT 块中使用了SUM,则会将所有数字类型字段统计出来将存入当前工作区(或表头);但一旦离开AT....ENDAT块后,又会将当前遍历的行恢复到工作区(或表头)中
DATA: BEGIN OF th_mseg OCCURS 10,
matnr TYPE mard-matnr, werks TYPE mard-werks,
lgort TYPE mard-lgort, shkzg TYPE mseg-shkzg,
menge TYPE mseg-menge, budat TYPE mkpf-budat,
LOOP AT th_mseg.
AT END OF shkzg."会根据shkzg及前面所有字段来进行分组
sum.
WRITE: / th_mseg-matnr, th_mseg-werks,th_mseg-lgort,
th_mseg-shkzg,th_mseg-menge,th_mseg-budat.
ENDAT.
ENDLOOP.
AS-101 2300 0001 S 10.000 ****.**.**
AS-100 2300 0002 S 10.000 ****.**.**
AS-100 2300 0001 S 20.000 ****.**.**
上面由于没有根据matnr + werks + lgort + shkzg 进行排序,所以结果中的第三行其实应该与第一行合并。其实这个统计与SQL里的分组(Group By)统计原理是一样的,Group By 后面需要明确指定分组的字段,如上面程序使用SQL分组写法应该为 Group By matnr werks lgort shkzg,但在ABAP里你只需要按照 matnr werks lgort shkzg按照先后顺序在结构定义的最前面进行声明就可表达了Group By那种意义,而且不一定要将matnr werks lgort shkzg这四个字段全部用在AT语句块中AT NEW、AT END OF shkzg 才正确,其实像上面程序一样,只写AT END OF shkzg这一个语句,前面三个字段matnr werks lgort都可以不用在AT语句中出现,因为ABAP默认会按照结构中声明的顺序将shkzg前面的字段也全都用在了分组中了
DATA: BEGIN OF line,
"C2、C3组件名声明的顺序一定要与在AT...... ENDAT块中使用的次序一致,即这里不能将C3声明在C2之前,且不能在C2与C3之间插入其他字段的声明
c2(5) TYPE c,
c3(5) TYPE c,
c4(5) TYPE c,
i1 TYPE i,
i2 TYPE i,
c1(5) TYPE c,
END OF line.
"使用在AT...... 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
如果循环的内表不是自己定义的,有时无法将分组的字段按顺序声明在一起,所以需要自己实现这些功能,下面是自己实现AT NEW与AT END OF(另一好处是在循环内表时可以使用Where条件语句)(注:使用这种只需要按照分组的顺序排序即可,如要分成bukrs与bukrs anlkl两组时,需要按照BY bukrs anlkl排序,而不能是BYanlkl bukrs):
DATA: lp_bukrs TYPE bukrs, "上一行bukrs字段的值
lp_anlkl TYPE anlkl. "上一行anlkl字段的值
"下面假设按bukrs,bukrs anlkl分成两组
SORT itab_data BY bukrs anlkl.
DATA: i_indx TYPE i .
DATA: lwa_data Like itab_data
LOOP AT itab_data where flg = ‘X‘.
i_indx = sy-tabix.
"**********AT NEW 对当前分组首行进行处理
IF itab_data-bukrs <> lp_bukrs. "Bukrs组
".........
ENDIF.
IF itab_data-bukrs <> lp_bukrs OR itab_data-anlkl <> lp_anlkl. "bukrs anlkl 分组
".........
ENDIF.
IF itab_data-bukrs <> lp_bukrs OR itab_data-anlkl <> lp_anlkl OR itab_data-.. <> lp_.. . "bukrs anlkl .. 分组
".........
ENDIF.
"**********普通循环处理
".........
"**********AT END OF 对当前分组末行进行处理
DATA : l_nolast1,l_nolast12 . "不是分组中最末行
"这里还是要清一下,以防该代码直接写在报表程序的事件里,而不是Form里(直接放在Report程序事件里时,l_nolast1,l_nolast12将会成为全局变量)
CLEAR: l_nolast1,l_nolast12,l_nolast...
DO.
i_indx = i_indx + 1.
READ TABLE itab_data INTO lwa_data INDEX i_indx."尝试读取下一行
IF sy-subrc <> 0."当前行已是内表中最后一行
EXIT.
"如果第一分组字段都发生了变化,则意味着当前行为所有分组中的最后行
"注:即使有N 个分组,这里也只需要判断第一分组字段是否发生变化,不
"需要对其他分组进行判断,即这里不需要添加其他 ELSEIF 分支
ELSEIF lwa_data-bukrs <> itab_data-bukrs.
EXIT.
ENDIF.
********断定满足条件的下一行不是分组最的一行
"如果Loop循环中没有Where条件,则可以将下面条件 lwa_data-flg = ‘X‘ 删除即可
IF sy-subrc = 0 AND lwa_data-flg = ‘X‘ .
IF lwa_data-bukrs = itab_data-bukrs ."判断当前行是否是 bukrs 分组最后行
l_nolast1 = ‘1‘.
IF lwa_data-nanlkl = itab_data-nanlkl ."判断当前行是否是 bukrs nanlkl 分组最后行
l_nolast2 = ‘1‘.
IF lwa_data-.. = itab_data-..."判断当前行是否是 bukrs nanlkl ..分组最后行
l_nolast.. = ‘1‘.
ENDIF.
ENDIF.
EXIT."只要进到此句所在外层If,表示找到了一条满Where条件的下一行数据,因此,只要找到这样的数据就可以判断当前分组是否已完,即一旦找到这样的数据就不用再往后面找了,则退出以防继续往下找
ENDIF.
ENDIF.
ENDDO.
IF l_nolast..IS INITIAL"处理 bukrs nanlkl ..分组
......
ENDIF.
IF l_nolast2 IS INITIAL ."处理 bukrs nanlkl 分组
......
ENDIF.
IF l_nolast1 IS INITIAL ."处理 bukrs 分组
......
ENDIF.
lp_bukrs = itab_data-bukrs.
lp_anlkl = itab_data-anlkl.
lp_.. = itab_data-.. .
ENDLOOP.
TYPES: BEGIN OF line ,
key ,
val TYPE i ,
END OF line .
DATA: itab1 TYPE line OCCURS 0 WITH HEADER LINE .
DATA: itab2 TYPE line OCCURS 0 WITH HEADER LINE .
itab1-key = 1.
itab1-val = 1.
APPEND itab1.
itab2 = itab1.
APPEND itab2.
itab1-key = 2.
itab1-val = 2.
APPEND itab1.
itab2 = itab1.
APPEND itab2.
LOOP AT itab1.
WRITE: / ‘itab1 index: ‘ , sy-tabix.
READ TABLE itab2 INDEX 1 TRANSPORTING NO FIELDS."试着读取其他内表
"READ TABLE itab1 INDEX 1 TRANSPORTING NO FIELDS."读取本身也不会影响后面的 MODIFY 语句
WRITE: / ‘itab2 index: ‘, sy-tabix.
itab1-val = itab1-val + 1.
"在循环中可以使用下面简洁方法来修改内表,修改的内表行为当前正被循环的行,即使循环中使用了
"READ TABLE语句读取了其他内表(读取本身也没有关系)而导致了sy-tabix 发生了改变,因为以下
"语句不是根据sy-tabix来修改的(如果在前面读取内表导致sy-tabix 发生了改变发生改变后,再使用
"MODIFY itab1 INDEX sy-tabix语句进行修改时,反而不正确。而且该语句还适用于Hash内表,需在
"MODIFY后面加上TABLE关键字后再适用于Hash表——请参见后面章节示例)
MODIFY itab1.
ENDLOOP.
LOOP AT itab1.
WRITE: / itab1-key,itab1-val.
ENDLOOP.
TYPES: BEGIN OF line ,
key ,
val TYPE i ,
END OF line .
DATA: itab1 TYPE HASHED TABLE OF line WITH HEADER LINE WITH UNIQUE KEY key.
DATA: itab2 TYPE line OCCURS 0 WITH HEADER LINE .
itab1-key = 1.
itab1-val = 1.
INSERT itab1 INTO TABLE itab1.
itab2 = itab1.
APPEND itab2.
itab1-key = 2.
itab1-val = 2.
INSERT itab1 INTO TABLE itab1.
itab2 = itab1.
APPEND itab2.
LOOP AT itab1.
WRITE: / ‘itab1 index: ‘ , sy-tabix. "循环哈希表时,sy-tabix永远是0
READ TABLE itab2 INDEX 1 TRANSPORTING NO FIELDS.
WRITE: / ‘itab2 index: ‘, sy-tabix.
itab1-val = itab1-val + 1.
MODIFY TABLE itab1. "注:该语句不一定在要放在循环里才能使用——循环外修改Hash也是一样的,这与上面的索引表循环修改是不一样的,并且修改的条件就是itab1表头工作区,itab1即是条件,也是待修改的值,修改时会根据内表设置的主键来修改,而不是索引号
ENDLOOP.
LOOP AT itab1.
WRITE: / itab1-key,itab1-val.
ENDLOOP.
三种类型第二索引:
2 UNIQUE HASHED: 哈希算法第二索引
2 UNIQUE SORTED: 唯一升序第二索引
2 NON-UNIQUE SORTED: 非唯一升序第二索引
TYPES sbook_tab TYPE STANDARD TABLE OF sbook
"主索引:如果要为主索引指定名称,则只能使用预置的 primary_key,但可以通过后面的 ALIAS 选项来修改(注:ALIAS选项只能用于排序与哈希表)
WITH NON-UNIQUE KEY primary_key "ALIAS my_primary_key
COMPONENTS carrid connid fldate bookid
"第一个第二索引:唯一哈希算法
WITH UNIQUE HASHED KEY hash_key
COMPONENTS carrid connid
"第二第二索引:唯一升序排序索引
WITH UNIQUE SORTED KEY sort_key1
COMPONENTS carrid bookid
"第三第二索引:非唯一升序排序索引
WITH NON-UNIQUE SORTED KEY sort_key2
COMPONENTS customid.
1、 可以在READ TABLE itab、MODIFY itab、DELETE itab、LOOP AT itab内表操作语句中通过WITH [TABLE] KEY key_name COMPONENTS K1=V1 ... 或者USING KEY key_name,语句中的key_name为第二索引名:
READ TABLE itab WITH TABLE KEY [key_name COMPONENTS] {K1|(K1)} = V1... INTO wa
READ TABLE itab WITH KEY key_name COMPONENTS {K1|(K1)} = V1... INTO wa
READ TABLE itab FROM wa [USING KEY key_name] INTO wa
READ TABLE itab INDEX idx [USING KEY key_name] INTO wa
MODIFY TABLE itab [USING KEY key_name] FROM wa
MODIFY itab [USING KEY loop_key] FROM wa此语句只能用在LOOP AT内表循环语句中,并且此时 USING KEY loop_key 选项也可以省略(其实默认就是省略的),其中loop_key是预定义的,不能写成其他名称
MODIFY itab INDEX idx [USING KEY key_name] FROM wa
MODIFY itab FROM wa [USING KEY key_name] ... WHERE ...
DELETE TABLE itab FROM wa [USING KEY key_name]
DELETE TABLE itab WITH TABLE KEY [key_name COMPONENTS] {K1|(K1)} = V1...
DELETE itab INDEX idx [USING KEY key_name|(name)]
DELETE itab [USING KEY loop_key]
DELETE itab [USING KEY key_name ] ... WHERE ...
DELETE ADJACENT DUPLICATES FROM itab [USING KEY key_name] [COMPARING K1 K2...]
LOOP AT itab USING KEY key_name WHERE... .
ENDLOOP.
2、 可以在INSERT itab与APPEND语句中通过USING KEY选项来使用第二索引
INSERT wa [USING KEY key_name] INTO TABLE itab
APPEND wa [USING KEY key_name] TO itab
DATA itab TYPE HASHED TABLE OF dbtab WITH UNIQUE KEY col1 col2 ...
"向内表itab中添加大量的数据 ...
READ TABLE itab "使用非主键进行搜索,搜索速度将会很慢
WITH KEY col3 = ... col4 = ...
ASSIGNING ...
上面定义了一个哈希内表,在读取时未使用主键,在大数据量的情况下速度会慢,所以在搜索字段上创建第二索引:
DATA itab TYPE HASHED TABLE OF dbtab
WITH UNIQUE KEY col1 col2 ...
"为非主键创建第二索引
WITH NON-UNIQUE SORTED KEY second_key
COMPONENTS col3 col4 ...
"向内表itab中添加大量的数据 ...
READ TABLE itab "根据第二索引进行搜索,会比上面程序快
WITH TABLE KEY second_key
COMPONENTS col3 = ... col4 = ...
ASSIGNING ...
"在循环内表的Where条件中,如果内表不是排序内表,则不会使用二分搜索,如果使用SORTED KEY,则循环时,会用到二分搜索?
LOOP AT itab USING KEY second_key where col3 = ... col4 = ... .
ENDLOOP.
标签:
原文地址:http://www.cnblogs.com/jiangzhengjun/p/4264685.html