# ABAP程式設計 基本概念 ###### tags: `ABAP程式設計` - fn+insert 取消 modify - ULINE."插入一行直線 - skip. "空格一行 - PARAMETERS 輸入(類似input) ### ABAP的資料形態 - C Character(文本域) - N Numeric Text - D Date ( YYYYMMDD ) - T Time ( HHMMSS ) - I Integer - F Floating Point Number - X Byte (字節字段) - P Packet Number ( 格式化數值 ) - STRING 文本字符串 **自行宣告資料形態** ``` types <user defined type> type <basic type> <user defined type> ``` ### ABAP的三種變數 * Element Data Object(單值變數) * Work Area(多值變數) * Internal Table(多行多列) #### 單值變數宣告 Element Data Object 1. TYPE +形態 **DATA** <VAR NAME> **TYPE** <ABAP dictionary type> *or* < user defined type> 2. LIKE(參考)+資料(變數)物件 **DATA** <VAR NAME> **LIKE** <DATA OBJECT> **範例:** ``` data pu(8) type c. pu = '靜宜大學'. data putel(10) type n VALUE '00000000'. WRITE:/ pu,putel. skip. ``` 輸出 `靜宜大學 00000000` ``` types teltype(10) type n. *自己定義了一個10個數字的電話形態 data millionTel type teltype value '0111111111' . *宣告了名為milliontel的teltype資料形態的單值變數,值為0111111111 data gigiTel like milliontel value '0123456789' . *gigitel 資料形態 參考(like)了milliontel的資料形態 WRITE:/ milliontel, gigitel. ``` 輸出 `0111111111 0123456789` ``` data text_line type c length 40. text_line ='a chapter on data types' . WRITE:/ text_line. data text_string type STRING. text_string = 'a program in abap ' . WRITE:/ text_string. data date type D. date = sy-datum. WRITE:/ date. ``` 輸出 ``` chapter on data types a program in abap 20221208 ``` --- #### 多值變數宣告 Work Area - 以多個欄位表示多個值(類似record)(希望一個變數純好幾個欄位) - 將多個變數組合在一個物件中,以利資料的處理 - 基本上就是一個Structure 1. 直接參考ABAP Dictionary 的TABLE結構 `DATA WA(這個work area的名字) TYPE Zpu111_57_art(參考的table 名字)` 實例 ``` data wa TYPE zpu111_57_art. *宣告一個變數,參考了art這個table wa-artid = 'x001'. *設定wa,參考之前的table裡面的欄位-artid的值為x001 wa-artname = 'pu'. wa-arturl = 'https://www.pu.edu.tw'. wa-arttel = '0123456789'. WRITE:/ wa-artid , wa-artname , wa-arturl , wa-arttel. ``` ``` skip. * 從zpu111_57_art 中讀取 *(全部)資料 (sql語法) select * from zpu111_57_art * into wa 表示 每讀一筆資料, 就把那筆資料複製到wa中 into wa. WRITE:/ wa-artid , wa-artname , wa-arturl , wa-arttel. ENDSELECT. * 在abap 裡面 select是一個迴圈的變數,所以要有endselect ``` 輸出![](https://i.imgur.com/qTEmp1h.png) 2. 先定義 STRUCTURE TYPE,再提供給 WROK AREA 使用(自定結構形態,再宣告變數) ``` TYPES: BEGIN OF <TYPE NAME>, FIELD1(LENTH) TYPE <ABAP DICTIONARY TYPE>, FIELD2(LENTH) TYPE <ABAP DICTIONARY TYPE>, END OF <TYPE NAME>. DATA <WA_NAME> TYPE <TYPE NAME>. ``` - 如果 FIELD 後面不接型態,就預設為 CHAR - 如果 FIELD 後面不接(長度),就預設為 (1) 實例 - 多筆資料查詢 ``` *PARAMETERS x1 type zpu111_57_art-artid. *PARAMETERS x2 type zpu111_57_show-team. PARAMETERS x type zpu111_57_look-artid. * text element 設定x要輸入什麼 → 劇院編號 (直接打勾綁定資料庫設定的) START-OF-SELECTION. WRITE x. data wa TYPE zpu111_57_show. * 不能直接在ABAP裡面讀取,因為會不知道是哪筆資料,所以會不知道要印table裡的哪一筆欄位 *因此必須先寫一個workarea,每讀一筆資料,寫入一筆資料 SELECT * from zpu111_57_show INTO wa WHERE team = x . WRITE :/ wa-showname. ENDSELECT. ``` - 單一一筆資料查詢 SINGLE ``` PARAMETERS x type zpu111_57_look-artid. START-OF-SELECTION. WRITE x. data wa2 TYPE zpu111_57_art. * 只找一筆資料 single SELECT SINGLE * from zpu111_57_art into wa2 where artid = x . WRITE:/ wa2-artid, wa2-artname, wa2-arttel, wa2-arturl. * 因為只有一筆 所以不用select結束 ``` 3. 直接使用 WORK AREA(直接宣告結構變數) ``` DATA: BEGIN OF <WA_NAME>, FIELD(LENTH) TYPE <ABAP DICTIONARY TYPE>, FIELD(LENTH) TYPE <ABAP DICTIONARY TYPE>, END OF <WA_NAME>. ``` 實例 ``` DATA: BEGIN OF S1, dep(4) type C, no(10) type n, name(10) TYPE c, END OF s1. s1-dep = '資管'. s1-no = '410870419'. s1-name = 'million'. write :/ s1-dep , s1-no , s1-name. ``` --- #### 多行多列變數宣告 Internal Table - 類似table的概念(但是屬於記憶體變數),多行多列。 - 有多個欄位並且可儲存多筆資料(多個structure的集合) - 類似MS ADO物件中的 Recordset (一個workarea只能存一筆資料,一個internal table 可以存多筆資料) - internal table 有三種形態(typekind) ![](https://i.imgur.com/g3ZOP8C.png) 1. standard table(一般常用的) 2. sorted table 3. hashed table ![](https://i.imgur.com/5FqDJXe.png) ##### Internal Table Type形態定義 ` TYPES <itabtype> TYPE <tabkind> OF <structure type> [WITH <key>]` 實例 ``` DATA WA TYPE ZPU111_57_ART. * 宣告一個internal table ,形態為 standard table ,參考了zpu111_57_art的結構 TYPES ITAB type STANDARD TABLE OF ZPU111_57_ART. data itab1 TYPE itab. skip. ``` 與workarea的區別 1. workarea-只能存一筆 ![](https://i.imgur.com/8YBRgZW.png) 2. internal table-能存多筆 ![](https://i.imgur.com/LgWoU2T.png) 實例 ``` DATA WA TYPE ZPU111_57_ART. * 為了不頻繁讀取資料庫,把資料庫的內容都丟進一個變數 * 宣告一個internal table ,形態為 standard table ,參考了zpu111_57_art的結構 TYPES ITAB type STANDARD TABLE OF ZPU111_57_ART. data itab1 TYPE itab. select * from zpu111_01_art INTO table itab1. skip. ``` 目前itab1內容 ![](https://i.imgur.com/KsgQ1MM.png) --- 因為itab是多筆資料的變數,所以如果直接loop的話,假設要印出itab-artid,系統會不知道是itab1的哪筆artid資料 ![](https://i.imgur.com/9XXmwYD.png) 執行後 ![](https://i.imgur.com/bc2vym8.png) - 解決方法1 -透過寫入wa中 ``` loop at itab1 into wa. WRITE:/ wa-artid, wa-artname, wa-arturl , wa-arttel. ENDLOOP. ``` - 解決方法2 WITH HEADER Line (直接用WITH HEAD LINE就不需要在寫入wa) ``` TYPES ITAB type STANDARD TABLE OF ZPU111_57_ART. DATA itab1 TYPE itab WITH header line. select * from zpu111_01_art INTO table itab1. loop at itab1 . WRITE:/ itab1-artid, itab1-artname, itab1-arturl , itab1-arttel. ENDLOOP. ``` ![](https://i.imgur.com/CO3Midj.png) - 補充 如果想要把結果輸出排序 順序 **SORT <ITABNAME> BY 欄位名字** 倒敘 **SORT <ITABNAME> BY 欄位名字 DESCENDING** ``` TYPES ITAB type STANDARD TABLE OF ZPU111_57_ART. DATA itab1 TYPE itab WITH header line. select * from zpu111_01_art INTO table itab1. SORT itab1 by arttel. loop at itab1 . WRITE:/ itab1-artid, itab1-artname, itab1-arturl , itab1-arttel. ENDLOOP. ``` ![](https://i.imgur.com/u5M6BRw.png) ` SORT itab1 by arttel DESCENDING.` ![](https://i.imgur.com/JAfmRGW.png) 1. 直接宣告、使用 ``` DATA: BEGIN OF <ITAB_NAME> OCCURS 0, FIELD(LENTH) TYPE <ABAP DICTIONARY TYPE>, FIELD(LENTH) TYPE <ABAP DICTIONARY TYPE>, END OF <ITAB_NAME>. ``` 2. 使用 LIKE ``` DATA <ITAB_NAME> TYPE/LIKE <ITAB_TYPE> WITH HEAD LINE. DATA <ITAB_NAME> TYPE/LIKE <TYPE_NAME> OCCURS 0 WITH HEAD LINE. ``` --- #### **補充-變量** 变量是用于在程序的分配的存储区域中存储值的命名数据对象。 顾名思义,用户可以在ABAP语句的帮助下更改变量的内容。 ABAP中的每个变量都有一个特定的类型,它决定了变量内存的大小和布局; 可以存储在该存储器内的值的范围; 以及可以应用于该变量的一组操作。 您必须先声明所有变量,然后才能使用它们。 变量声明的基本形式是 `DATA <f> TYPE <type> VALUE <val>. ` 这里<f> 指定变量的名称。 变量的名称最多可包含30个字符。 <type> 指定变量的类型。 具有完全指定的技术属性的任何数据类型被称为<type&gt></type&gt;.>; <val> 指定<f>的初始值变量。 在定义基本固定长度变量的情况下,DATA语句会自动使用类型特定的初始值填充变量的值。 <val>的其他可能值可以是文字,常量或显式子句,例如Is INITIAL。 以下是变量声明的有效示例。 ``` DATA d1(2) TYPE C. DATA d2 LIKE d1. DATA minimum_value TYPE I VALUE 10. ``` 在上面的代码片段中,d1是C类型的变量,d2是d1类型的变量,minimum_value是ABAP整数类型的变量。 ``` DATA ResearchRoom TYPE I VALUE 579. DATA MoonToEarth TYPE F VALUE 384401. CONSTANTS pi TYPE P DECIMALS 2 VALUE '3.14'. WRITE:/ ResearchRoom, MoonToEarth, pi. ``` 輸出 ![](https://i.imgur.com/llWKLcj.png) ABAP中有三種變量 1. Static Variables 靜態變量 2. Reference Variables 參考變量 語法為 **DATA** <ref> **TYPE REF TO** <type> **VALUE IS INITIAL.** 3. System Variables 系統變量 --- ### 常用的系統參數 - **Sy-datum** - Date and time, current application server date - **Sy-uzeit** - Date and time, current application server time - **Sy-subrc** - Return value after ABAP statements - Ex: 搜尋資料庫時,至少找到一筆資料,則其值為 0 - 如果subrc = 0 表示至少有找到一筆資料, 如果 不等於0 表示一筆資料都找不到。 - **Sy-lsind** - List processing, details list index (表示Detail List處在第幾層) --- ### ABAP 運算子與邏輯判斷 #### 運算子 ABAP 運算子分為四類 1. 比較運算子 ` =`(EQ) : 相等測試,檢查兩個操作數的值是否相等,如果是,則條件為真。示例(A=B)不為真。 ` <>`(NE) : 不等式檢驗,檢查兩個操作數的值是否相等,如果值不相等,則條件為真。示例(A<>B)為真。 ` > `(GT) : 大於測試,檢查左操作數的值是否大於右側的值,如果是,這條將變為TRUE。示例(A>B)不為真。 ` <`(LT) : 小於測試,檢查左操作數的值是否小於右側的值,如果是,則條件變為TRUE。示例(A<B)不為真。 ` <=` (LE) : 小於或等於測試 ` >= `(GE) : 大於等於測試 `IS INITIAL` : 如果变量的内容没有改变,并且它已被自动赋予其初始值,则条件为真。 示例(A IS INITIAL)不为真。 實例: ``` DATA: A TYPE I VALUE 115, B TYPE I VALUE 119. IF A LT B. WRITE: / 'A is less than B'. ENDIF. ``` 輸出`A is less than B` ``` DATA: A TYPE I. IF A IS INITIAL. WRITE: / 'A is assigned'. ENDIF. ``` 輸出`A is assigned` 2. 邏輯運算子 AND , OR 3. 算數運算子 +, - , * , / , mod(餘數) 實例: ``` REPORT YS_SEP_08. DATA: A TYPE I VALUE 150, B TYPE I VALUE 50, Result TYPE I. Result = A / B. WRITE / Result. ``` 輸出`3` 4. 字符串運算子 - **CO** 檢查A是否僅由B中的字符組成 - **CN** 檢查A是否包含不在B中的字符 - **CA** 檢查A是否至少包含一個字符B - **NA** 檢查A是否不包含任何字符B - **CS** 檢查A是否包含字符串B - **NS** 檢查A是否不包含字符串B 實例: ``` DATA: P(10) TYPE C VALUE 'APPLE', Q(10) TYPE C VALUE 'CHAIR'. IF P CA Q. WRITE: / 'P contains at least one character of Q'. ENDIF. ``` 輸出`P contains at least one character of Q` --- #### 控制式 - IF子句 ``` IF <Logical Expression> . <Statements>. ELSEIF <Logical Expression> . <Statements>. ELSE . <Statements>. ENDIF . ``` 實例 ``` PARAMETERS x type i. PARAMETERS opt type c. PARAMETERS y type i. START-OF-SELECTION. *完成選擇屏幕上字段的初始值設定及檢查後,開始讀取數據之前觸發 WRITE:/ sy-datum, sy-uzeit. data result type p decimals 2. if opt = '+'. result = x + y. WRITE:/ 'result:' , result. elseif opt = '-'. result = x - y. write:/ 'result', result. elseif opt = '*'. result = x * y. write:/ 'result', result. elseif opt = '/'. result = x / y . write:/ 'result', result. else. WRITE:/ '運算符號請輸入+、-、*、/ '. ENDif. ``` - CASE 子句 ``` CASE < variable > . WHEN 'value1' . <Statements>. WHEN 'value2' OR 'value3' . <Statements>. WHEN OTHERS . <Statements>. ENDCASE . ``` 實例 ``` PARAMETERS x type i. //建立一個可以輸入值x,形態為i PARAMETERS opt type c. PARAMETERS y type i. START-OF-SELECTION. *完成選擇屏幕上字段的初始值設定及檢查後,開始讀取數據之前觸發 WRITE:/ sy-datum, sy-uzeit. data result type p decimals 2. case opt. when'+'. result = x + y. WRITE:/ 'result:' , result. when'-'. result = x - y. write:/ 'result', result. when '*'. result = x * y. write:/ 'result', result. when '/'. result = x / y . write:/ 'result', result. when others. WRITE:/ '運算符號請輸入+、-、*、/ '. ENDCASE. ``` 輸出 ![](https://i.imgur.com/TPn0NbG.png) 執行後 ![](https://i.imgur.com/kgiFuBF.png) --- ### 迴圈 - while loop - do loop - nested loop #### WHILE LOOP - 當給定條件為真時,重複一個語句或一組語句。 ``` WHILE log_exp [statement_block] ENDWHILE. ``` 實例 1 ``` while i < 10. i = i + 1. WRITE :/ i . ENDWHILE. ``` 輸出 ``` 1 2 3 4 5 6 7 8 9 10 ``` 實例 2 ``` data a TYPE i value 0. while a <> 8. *檢驗a 與右側值是否相等,如果值不相等,則條件為TRUE。 WRITE:/ 'this is the line:', a. a = a + 1. endwhile. ``` 輸出 ``` This is the line: 0 This is the line: 1 This is the line: 2 This is the line: 3 This is the line: 4 This is the line: 5 This is the line: 6 This is the line: 7 ``` #### DO LOOP - DO 語句對於特定任務重複特定次數很有用。 ``` DO 整數變數 TIMES. [statement_block] ENDDO. ``` 實例 ``` data i TYPE i VALUE 0. Do 10 times. i = i + 1. WRITE:/ i. ENDDO. ``` 輸出 ``` 1 2 3 4 5 6 7 8 9 10 ``` #### NESTED LOOP - 在任何一個WHILE 或DO 循環中使用一個或多個循環。 #### 控制循環語句 - CONTINUE 導致循環跳過其身體的剩餘部分,並開始下一個循環傳遞。 範例 ``` data a TYPE i value 0. DO 5 TIMES. a = a + 1 . if a = 3 . continue. ENDIF. WRITE :/ a. ENDDO. ``` 輸出 ``` 1 2 4 5 ``` - CHECK 如果條件為假,則在CHECK之後的剩餘語句被忽略,並且系統開始下一循環通過。 - EXIT 完全終止循環,並將執行轉移到循環後立即執行的語句。 --- ### 模塊化技術 - 模塊化 是程序的重要思想,主要作用有 1. 結構清晰、易讀、易於維護 2. 實現代碼複用 3. 實現數據封裝 目前大多數實例都放與 START-OF-SELECTION,這裡介紹幾種**過程模塊化技術** - **子程序**(Subroutine) - **功能模塊**(Function Modules) #### SUBROUTINE 副程式 - 被視為程序內部的模塊化實現,值被定義為某一個程序調用。 - 第一行以FORM開始,最後一行以ENDFORM結束。 ![](https://i.imgur.com/Q5Gvnv5.png) - 三種傳值方式 > **USING VALUE** 呼叫一段副程式去執行,把值傳給他計算,算完後回來,就算值改變了也不會寫回去 > **CHANGING VALUE** 把值傳給他 ,跑著跑著再改寫值(不同位置,但回傳後更改其值) > **CHANGING** 呼叫的時候傳同一個記憶體空間,變數改變之後,回來的值也會改變(相同記憶體位置) ![](https://i.imgur.com/RQOmJuX.png) 實例 **USING VALUE** ``` data x type I VALUE 5. * 第一種寫法 using value * 主程式 perform 呼叫副程式第一種寫法 using PERFORM square USING x . WRITE :/ 'x=' , x. * 定義一個form 名字為square form square using value(y). y = y * y . WRITE :/ 'y=' , y. * 結束 ENDFORM. ``` 輸出![](https://i.imgur.com/kHvSgzn.png) 註:只是值傳給副程式計算,計算完後並不會改寫 [詳細筆記補充](詳細筆記[https://www.twblogs.net/a/5e547a50bd9eee2117c51ccc](https://)) --- ### EVENT BLOCK - 類似視窗系統之事件,無一定之執行順序,而由runtime system 所決定 - 用法: - 第一行以Keyword為起始,無結束keyword - 直到遇到下一個event block 或 form keyword才結束 - 事件流(6個) - INITIALIZATION(初始化) - AT SELECTION-SCREEN(屏幕跳出前) - START-OF-SELECTION(取数据) - END-OF-SELECTION(展示数据) - TOP-OF-PAGE(普通报表输出页头) - END-OF-PAGE(普通报表输出页尾) #### LOAD-OF-PROGRAM: 程式開始執行時候自動調用 這個事件在SUBMIT, CALL TRANSACTION, PERFORM 等執行的時候會自動調用這個事件,所以無需聲明即可。 #### INITIALIZATION - 只能用於報表程序 - 在選擇屏幕出現之前執行,如果用邏輯數據庫的話,這個是唯一能夠修改屏幕初始值的地方 - 通常的用法是在這裡給選擇屏幕中的字段賦值 #### AT SELECTION-SCREEN - 其实就像一个FORM,所以在这个事件里声明的变量都是局部变量。 - 根据SY-UCOMM这个系统变量可以判断用户的命令 - 在这个事件里响应的是屏幕上选择条件中的事件,例如CHECKBOX的选择与否,RADIOBUTTON的选择,LISTBOX的选择等等。所以分为以下几个方面: - ON psel :在PARAMETER变化是触发的事件 - ON END OF sel :SELECT-OPTION触发的事件 - ON VALUE-REQUEST FOR psel_low_high :选择的帮助(F4) - ON HELP-REQUEST FOR psel_low_high :选择的帮助(F1) - ON RADIOBUTTON GROUP radi :单选按钮事件 - ON BLOCK block :框架的触发事件 - OUTPUT :响应屏幕上的事件,修改选择屏幕的唯一方法 #### START-OF-SELECTION 报表程序必须执行的事件,在进入第二屏幕之前触发。 #### END-OF-SELECTION 第二屏幕显示完毕,结束处理。