为了不在数据库表上直接操作。
我们在内存里建了个表,然后把数据库表的数据复制过来。这些内表,我们可以用来做关联啥的。
有些时候我去内表找数据,需要遍历。
我们来抽丝剥茧。这个遍历是个啥啊。。。是一行一行的找么。
我今天突然觉得这个take place这个词组很有意思,拿一个空间来。这个事情就能发生,举行。
我要干啥事,我得有地方来干。得take一个place。
跟计算机讲,我要干什么干什么,前提是我的东西得有地方放。在什么时候放,我都得事无巨细的告诉它。
我要用数据库的表了。
我得先声明 tables: vbap.
然后我这个咋操作呢,我如果就只要用它一个表里的内容,那我就先建一个结构。结构里有一些type的字段。这是个二维的表框框。然后我要take place。要一个type table of的内表空间,还要个work area。
2021.11.24回头看,写的啥玩意*
新写的有了更深的理解:
内表.
好了,然后我把需要的字段从数据库表select出来,into我自己的新建的内表。
条件是啥呢?根据啥来选呢?就where,满足我参数或者select options条件的。
好了,我数据都有了。
接下来进行操作了。
文章目录
对表中的数值进行合计
这个place有了。给你个地盘了。
接下来呢,还得一步步的告诉计算机。到底啥时候干啥事。
如果我要对表中列里面的值进行合计。
比如说我有物料编号,我需要统计不同物料的价值。
那物料编号,必然的,有很多个。
SORT
我一步步的,我得先把这个物料编号排下序。
那么现在我就来把这个表SORT一下。
SORT it_vbap BY matnr.
于是,所有一个物料编号的,会从上排到下。
在这个内表里。
接下来,干啥呢?
当这些物料编号一样的,我就统计它的value值啊。
这个表里我只有一个可以合并的value值。
那我怎么来统计呢?
我得告诉计算机,啥时候开始计算。
那么event得来上场,因为我需要event来触发。
到了什么event了,然后来触发什么事情。
所有这些操作由于是在表里一行一行的弄。
所以我们需要先把表loop到工作区间里。
LOOP
SORT完了这个表,然后我们把表的行一行一行的loop进到work area里面去。
loop at it_vbap into wa_vbap.
AT FIRST
开始启用这个event,意思是在对表行进行操作之前,要做啥。
做啥呢?要输出表头啊。
于是 AT FIRST.
WRITE : /‘material’ color 2, 12 ‘value’ color 30.
ENDAT.
以上,只是展示了一个表头。
就是告诉它,在表行开头,干啥。
AT END OF
那么还有一个event,at end of 一个字段。
是啥意思呢?
就是我如果有很多个行的值是一样的,到下一行不一样了。
就是这个一样的值end了。
那我可以从这里来进行一个sum.
AT END OF matnr.
sum.
WIRTE: / wa_vbap- matnr color 3 ,wa_vbap-value color 5.
ENDAT.
SUM就是去总计可以加的值类型。你C类型的,它就不加了。
你想显示什么,就可以只显示什么。
如果你只想显示一个统计值。那么就可以只显示一个统计值。
可以在AT END OF 之前,write所有要展示的,这样会形成一个独立的一行累加值。
最后ENDLOOP.
好了,也就是我在一个循环中,对每行的数据at first 和 at end of field进行了一些事件触发,以及做了一些操作。
现在,我想让相同的行编号值隐身,怎么弄呢?
那就是还要有另外一个事件来触发。
这时,怎么实现这种功能呢?怎么压缩它以下的这些相同的列呢?
就是说,当我是一个新的行,那你可以展示其余的列值,当我是个重复的行编号,那可以压缩我,不展示我。
AT NEW
展示不展示我,取决于我是不是一个新行值。
这里还得借助一个event,就是at new。
AT NEW vbeln.
当我这个编号是新的。
我展示我所有的列值。就是write所有的列值。
当我的编号不是新的,怎么办呢?
我就不展示了,是的。我只展示其余的列值。
可是这个是个event啊。它不是个可以判断的值啊。我需要判断它是不是个新值。
我需要给它附加个附庸。
我需要来定义一个变量,data new_po type c.
我需要让它成为可判断是否为新行的at new,于是在AT NEW这个event下面,我们直接来定义一个值。
AT NEW VBELN.
NEW_po = ‘x’.
ENDAT.
那么现在怎么来做判断?
当然是IF
IF new_po = ‘x’.
write: / ****
new_po = ’ '. (同时给这个变量赋值成空。)
ENDIF.
IF new_po = ’ '.
WRITE: / **.
ENDIF.
这个事件会一直执行,到下个事件出现为止。下个事件就是at end of vbeln.
回到这里,会发现有个错误。
就是,当你去查找一个新的行,那么,这个行,设置了一个flag是X。于是我输出第一行,然后我就把这行上的这个flag给设置成空。然后这个空会立刻又执行,于是我下一个if,又会把这行再执行一遍。
就等于第一行,我执行了两遍。
然后我会一直执行下去直到新的行。
这就不行了。
我不需要第一行执行两遍。怎么让它不执行两遍?
首先你得直到它为什么执行了两遍。
因为。我第一行先赋值了X,于是我接下来输出第一行。
然后我赋值了空,我得到第二行再继续输出。可是下面的IF,又满足了,我会持续输出第一行。
这个需要debug。
所以我输出两遍。
那么,我来改下:
IF new_po = ‘x’.
write: / ****
new_po = ’ '. (同时给这个变量赋值成空。)
ELSE.
new_po = ’ '.
WRITE: / **. (这一句不会被执行,因为条件会直接被筛选进第一个if,不会进入这个else)
ENDIF.
adjecent duplicates
毗连重复
我要删除掉一行的重复值。首先排序。
delete adjecent duplicates from it_vbap.
TABLES : vbap.
SELECT-OPTIONS : s_vbeln FOR vbap-vbeln,
s_matnr FOR vbap-matnr.
TYPES : BEGIN OF ty_vbap,
vbeln TYPE vbeln,
posnr TYPE posnr,
matnr TYPE matnr,
netwr TYPE netwr,
END OF ty_vbap.
DATA : it_vbap TYPE TABLE OF ty_vbap,
wa_vbap TYPE ty_vbap.
DATA : new_po TYPE c.
SELECT vbeln posnr matnr netwr FROM vbap INTO TABLE it_vbap
WHERE vbeln IN s_vbeln
AND matnr IN s_matnr.
SORT it_vbap BY vbeln.
LOOP AT it_vbap INTO wa_vbap.
AT FIRST.
WRITE :/ 'Order' COLOR 1, 12 'item' COLOR 2, 19 'Material' COLOR 2, 50 'Value' COLOR 3.
ENDAT.
AT NEW vbeln.
new_po = 'X'.
ENDAT.
IF new_po = 'X'.
WRITE :/ wa_vbap-vbeln, wa_vbap-posnr, wa_vbap-matnr, wa_vbap-netwr.
new_po = ' '.
Else.
WRITE :/12 wa_vbap-posnr, wa_vbap-matnr, wa_vbap-netwr.
ENDIF.
AT END OF vbeln.
SUM.
WRITE :/39 wa_vbap-netwr COLOR 5.
ENDAT.
ENDLOOP.
READ table
当你去读表,那你要把表读到哪里?
读到工作区里。
read table it_vbap into wa_vbap INDEX 5.
也就是说,read只能读一行。
那么read其实有两种方式。在选择上,要么是选行数,要么给它个选项:
read table it_vbap into wa_vbap with key matnr = ‘M-01’.
key是列的意思。
但是read只能读一列,如果满足条件的不止一列呢?
那只有第一条满足条件的被读到。其他的就被ignore。
如果读到了,那就会有个值返回: sy-subrc = 0
除了以上写法,也可以写成:
read table it_vbap with key matnr = ‘M-01’ into wa_vbap.
APPEND
不得不说,这个的意思是附加。
也就是说本来人家都有了,你再加个。
那么一般是你有表的内容了,然后append一个wa_area的一行到表里面去。
append不仅仅是可以附加一行,也可以附加好几行。
也就是append lines of it_vbak1 to it_vbak.
对表进行join
要知道,并不是所有时候,表的join都是通过主键来进行的。
当我和别人join的不是主键,比如我要取得一个属性的文本,那我这个join的是我的一个属性值和别人的主键值。
这种就不会像主键那么快,因为他可能不唯一。
Join确实很好用。但是有些时候。我们要join的表很大,而且不是join它们的共同主键,那这时候,我join到三个表以上,就会相当影响性能了。
因为你得去遍历表啊,需要时间的。
比如说我需要的数据来自5个表。是的,干啥之前你得把需要的表理清关系。也就是你得知道你的表里有哪些数据,然后这些表的列都是啥意思,表列直接有啥包含关系。
而其中有两个表是有共同主键的。那这时候,我可以join这两个表。
一般就是select * * * * from table a as a inner join table b as b on a~A = b~A where * = parameter into table X.
而之前我们也看过了。
除了inner join之外,还可以用: for all entries in
for all entries in
也就是说这个也可以。
那怎么使用的呢?前面得有个主句表啊。就是说我前面已经把数据都拉进一个表了,然后后面还有一个表。
那么这个后面的表,得是个有值的表,啥意思呢?
就是要么你是从内表select几个字段已经到了你自定义的表。
要么你是已经join了的into的一个表。
然后我select *** from tableA into table it_tableA for all entries in tableB where it_tableA~a = tableB~A
这样我就把it_tableA里面的所有和B表的有相同键值的行给取到it_tableA里了。也就是做了个限制了。
但是这样免去了写很多的inner join。
而且也填充了我们需要的数据到这几个表中。当你必须要连接好多个表,而且这些表没有共同主键,那你就只能这么用。
用 for all entries in / move corresponding / read table / append /clear
TABLES: vbak, " Order Data
tvakt, " Order Description text table
tvzbt, " Payment terms text table
vbkd, " Order business data ( like payment terms , customer groups etc )
t151t. " customer groups text table
*Join of VBAK and VBKD
TYPES : BEGIN OF ty_vbak_vbkd,
vbeln TYPE vbak-vbeln,
auart TYPE vbak-auart,
erdat TYPE vbak-erdat,
ernam TYPE vbak-ernam,
kdgrp TYPE vbkd-kdgrp,
zterm TYPE vbkd-zterm,
END OF ty_vbak_vbkd,
* Order Type Description from table TVAKT
BEGIN OF ty_tvakt,
auart TYPE tvakt-auart,
bezei TYPE tvakt-bezei,
END OF ty_tvakt,
* Payment Terms
BEGIN OF ty_tvzbt,
zterm TYPE tvzbt-zterm,
vtext TYPE tvzbt-vtext,
END OF ty_tvzbt,
*Customer group texts from T151T
BEGIN OF ty_t151t,
kdgrp TYPE t151t-kdgrp,
ktext TYPE t151t-ktext,
END OF ty_t151t,
*Final structure to be written out on to the screen
BEGIN OF ty_final,
vbeln TYPE vbak-vbeln,
auart TYPE vbak-auart,
erdat TYPE vbak-erdat,
ernam TYPE vbak-ernam,
kdgrp TYPE vbkd-kdgrp,
zterm TYPE vbkd-zterm,
bezei TYPE tvakt-bezei,
vtext TYPE tvzbt-vtext,
ktext TYPE t151t-ktext,
END OF ty_final.
*Internal tables
DATA : it_vbak_vbkd TYPE TABLE OF ty_vbak_vbkd,
it_tvakt TYPE TABLE OF ty_tvakt,
it_tvzbt TYPE TABLE OF ty_tvzbt,
it_t151t TYPE TABLE OF ty_t151t,
it_final TYPE TABLE OF ty_final,
wa_vbak_vbkd TYPE ty_vbak_vbkd,
wa_tvakt TYPE ty_tvakt,
wa_tvzbt TYPE ty_tvzbt,
wa_t151t TYPE ty_t151t,
wa_final TYPE ty_final.
SELECT-OPTIONS :
s_vbeln FOR vbak-vbeln,
s_auart FOR vbak-auart,
s_erdat FOR vbak-erdat,
s_ernam FOR vbak-ernam,
s_zterm FOR vbkd-zterm,
s_kdgrp FOR vbkd-kdgrp.
START-OF-SELECTION.
SELECT vbak~vbeln
vbak~auart
vbak~erdat
vbak~ernam
vbkd~kdgrp
vbkd~zterm
FROM vbak AS vbak
INNER JOIN vbkd AS vbkd
ON vbak~vbeln = vbkd~vbeln
INTO TABLE it_vbak_vbkd
WHERE vbak~vbeln IN s_vbeln
AND vbak~auart IN s_auart
AND vbak~erdat IN s_erdat
AND vbak~ernam IN s_ernam
AND vbkd~posnr = '000000'
AND vbkd~zterm IN s_zterm
AND vbkd~kdgrp IN s_kdgrp.
IF it_vbak_vbkd[] IS NOT INITIAL.
SELECT auart bezei
FROM tvakt
INTO TABLE it_tvakt
FOR ALL ENTRIES IN it_vbak_vbkd
WHERE auart = it_vbak_vbkd-auart
AND spras = sy-langu.
SELECT zterm vtext
FROM tvzbt
INTO TABLE it_tvzbt
FOR ALL ENTRIES IN it_vbak_vbkd
WHERE zterm = it_vbak_vbkd-zterm
AND spras = sy-langu.
SELECT kdgrp ktext
FROM t151t
INTO TABLE it_t151t
FOR ALL ENTRIES IN it_vbak_vbkd
WHERE kdgrp = it_vbak_vbkd-kdgrp
AND spras = sy-langu.
ENDIF.
LOOP AT it_vbak_vbkd INTO wa_vbak_vbkd.
MOVE-CORRESPONDING wa_vbak_vbkd TO wa_final. *此处是一行一行的,把第一个工作区间一行的列转移到目标工作区间的一行的其中相对应的列。然后其余的在这行上面的列,在下面的表上面读取。
READ TABLE it_tvakt INTO wa_tvakt WITH KEY auart = wa_vbak_vbkd-auart. *注意这个语法,read table into with key/ loop at into where 那么with的这个key值,是相对于已经存在于上面的工作区的,也就是我们第一个loop的工作区。因为那是第一行。
IF sy-subrc = 0.
MOVE wa_tvakt-bezei TO wa_final-bezei.*如果有值了,再把这个值放到目标工作区。在loop里面的read,也是一行一行的读。所以说不能在loop里面再套一个loop了,那是双重循环了。
ENDIF.
READ TABLE it_tvzbt INTO wa_tvzbt WITH KEY zterm = wa_vbak_vbkd-zterm.
IF sy-subrc = 0.
MOVE wa_tvzbt-vtext TO wa_final-vtext.
ENDIF.
READ TABLE it_t151t INTO wa_t151t WITH KEY kdgrp = wa_vbak_vbkd-kdgrp.
IF sy-subrc = 0.
MOVE wa_t151t-ktext TO wa_final-ktext.
ENDIF.
APPEND wa_final TO it_final.* 最后把值append进table
CLEAR wa_final.
ENDLOOP.
BREAK-POINT.