內表是每個ABAP開發人員都必須懂的,數據從R3取出來后,就是放在內表里處理的,其實就是java中的集合框架,只是沒有那么多不同數據結構的內表,目前只有標準、排序、Hash三種,這還是新的語法,老的只有個標準的,關于內表這方面的定義、性能,以后我專貼一篇文章吧。這里只是對內表的常用操作,這也是項目中用得最多的點!
COLLECT [<wa>INTO] <itab>將具有相同關鍵字段值的行中同名的數字字段的值累計到一條記錄上,只有非表關鍵字段被累加;當在內表中找不到指定的被累加行時,COLLECT語句的功能與APPEND語句是一樣的,即將一個工作區的內容附加到itab內表中。使用COLLECT操作的內表有一個限制,即該的行結構中,除了表鍵字段以外的所有字段都必須是數字型(i、p、f)
INSERT <wa>INTO TABLE <itab>."單條插入
INSERT LINES OF <itab1> [FROM <n1>] [TO <n2>]INTO TABLE<itab2>"批量插入
向UNIQUE的排序表或哈希表插入重復的數據時,不會拋異常,但數據不會被插入進去,這與APPEND是不一樣的
"只要根據關鍵字或索引在內表中讀取到相應數據,不管該數據行是否與COMPARING指定的字段相符,都會存儲到工作區
READ TABLE <itab>WITH KEY{<k1> = <f1> ... <kn> = <fn>...[BINARY SEARCH] }
INTO <wa> [COMPARING <f1><f2> ...|ALL FIELDS]
[TRANSPORTING <f1><f2> ...|ALL FIELDS|NO FIELDS]
|ASSIGNING <fs>
READ TABLE <itab> FROM <wa>…以表關鍵字為查找條件,條件值來自<wa>
COMPARING:系統根據<k1>...<kn>(關鍵字段)讀取指定的單行與工作區<wa>中的相應組件進行比較。
如果系統找根據指定<k1>...<kn>找到了對應的條目,且進行比較的字段內容相同,則將 SY-SUBRC 設置為0,如果進行比較的字段內容不同,則返回值 2;如果系統根據<k1>...<kn>找不到條目,則包含 4。如果系統找到條目,則無論比較結果如何,都將其讀入wa中
MODIFY TABLE<itab>FROM <wa> [TRANSPORTING <f1> <f2> ...]"修改單條(MODIFY TABLE <itab>一般用在循環中修改哈希表,且itab內表帶表頭)。這里的<wa>扮演雙重身份,不僅指定了要修改的行(條件),還包括要修改的新的值。系統以整個表的所有關鍵字段來搜索要修改的行;USING KEY:如果未使用此選項,則會使用默認的主鍵PRimary table key來修改相應的行;如果找到要修改的行,則將<wa>中所有非關鍵字段的內容拷貝到對應的數據行中對應的字段上;如果有多行滿足條件時只修改第一條
MODIFY <itab>FROM <wa> TRANSPORTING<f1><f2>...WHERE<cond>"修改多條
DELETE TABLE<itab> FROM <wa> "刪除單條。多條時,只會刪除第一條。條件為所有表關鍵字段,值來自<wa>
DELETE TABLE <itab> WITHTABLE KEY <k1> = <f1> ..."刪除單條。多條時只會刪除第一條,條件為所有表關鍵字
DELETE itabWHERE ( col2 > 1 ) AND ( col1 < 4 )"刪除多行
DELETE ADJACENTDUPLICATES FROM <itab> [COMPARING<f1><f2> ... |ALL FIELDS]
注,在未使用COMPARING選項時,要刪除重復數據之前,一定要按照內表關鍵字聲明的順序來進行排序,才能刪除重復數據,否則不會刪除掉;如果指定了COMPARING選項,則需要根據指定的比較字段順序進行排序(如COMPARING <F1><F2>時,則需要sort by <F1><F2>,而不能是sort by <F2><F1>),才能刪除所有重復數據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 {INTOwa}|{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 aLOOP , 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 resultIf you delete lines behind the current line, the deleted lines will no longer be processed in the subsequent loop passesIf 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 affectssy-tabix in the subsequent loop pass如果在 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 Bymatnr 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 USING3 'c' 'aa' 'aaa' '3333'33.PERFORM append USING 4'd' 'aa' 'bbb' '4444' 44.PERFORM append USING5 'e' 'bb' 'aaa' '5555'55.PERFORM append USING 6'f' 'bb' 'bbb' '6666' 66.PERFORM append USING7 '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 Ivalue(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_bukrsTYPE 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_bukrsOR itab_data-anlkl <> lp_anlkl."bukrs anlkl 分組 "......... ENDIF. IF itab_data-bukrs <> lp_bukrsOR itab_data-anlkl <> lp_anlklOR 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 ANDlwa_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: itab1TYPE line OCCURS 0WITH HEADER LINE .DATA: itab2TYPE line OCCURS 0WITH 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: itab1TYPE HASHED TABLE OF line WITH HEADER LINE WITH UNIQUE KEY key.DATA: itab2TYPE line OCCURS 0WITH HEADER LINE .itab1-key =1.itab1-val = 1.INSERT itab1 INTO TABLEitab1.itab2 = itab1.APPEND itab2.itab1-key =2.itab1-val = 2.INSERT itab1 INTO TABLEitab1.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 TABLEOF sbook "主索引:如果要為主索引指定名稱,則只能使用預置的 primary_key,但可以通過后面的 ALIAS 選項來修改(注:ALIAS選項只能用于排序與哈希表) WITH NON-UNIQUE KEY primary_key "ALIAS my_primary_key COMPONENTS carrid connid fldate bookid "第一個第二索引:唯一哈希算法 WITH UNIQUE HASHED KEYhash_key COMPONENTS carrid connid "第二第二索引:唯一升序排序索引 WITH UNIQUE SORTEDKEY sort_key1 COMPONENTS carrid bookid "第三第二索引:非唯一升序排序索引 WITH NON-UNIQUE SORTED KEYsort_key2 COMPONENTS customid.
1、 可以在READ TABLE itab、MODIFY itab、DELETE itab、LOOP AT itab內表操作語句中通過WITH [TABLE] KEYkey_nameCOMPONENTSK1=V1 ...或者USING KEY key_name,語句中的key_name為第二索引名:
READ TABLE itab WITH TABLE KEY[key_nameCOMPONENTS] {K1|(K1)}= V1...INTO wa
READ TABLE itab WITH KEYkey_nameCOMPONENTS {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 [USINGKEY loop_key]FROM wa此語句只能用在LOOP AT內表循環語句中,并且此時 USING KEY loop_key 選項也可以省略(其實默認就是省略的),其中loop_key是預定義的,不能寫成其他名稱
MODIFY itab INDEXidx [USING KEY key_name]FROM wa
MODIFY itab FROMwa [USING KEY key_name] ...WHERE ...
DELETE TABLE itab FROM wa [USING KEYkey_name]
DELETE TABLE itab WITH TABLE KEY[key_nameCOMPONENTS] {K1|(K1)}= V1...
DELETE itab INDEXidx [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 KEYkey_name WHERE... . ENDLOOP.
2、 可以在INSERTitab與APPEND語句中通過USING KEY選項來使用第二索引
INSERT wa [USING KEY key_name]INTO TABLE itab
APPEND wa [USING KEYkey_name] TO itab
DATA itab TYPE HASHED TABLE OFdbtab 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 KEYsecond_key where col3 = ... col4 = .... ENDLOOP.
原文出自 SAP師太技術博客,博客鏈接:www.cnblogs.com/jiangzhengjun新聞熱點
疑難解答