# 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
```
輸出
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)

1. standard table(一般常用的)
2. sorted table
3. hashed table

##### 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-只能存一筆

2. internal table-能存多筆

實例
```
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內容

---
因為itab是多筆資料的變數,所以如果直接loop的話,假設要印出itab-artid,系統會不知道是itab1的哪筆artid資料

執行後

- 解決方法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.
```

- 補充 如果想要把結果輸出排序
順序 **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.
```

` SORT itab1 by arttel DESCENDING.`

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.
```
輸出 
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.
```
輸出

執行後

---
### 迴圈
- 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結束。

- 三種傳值方式
> **USING VALUE** 呼叫一段副程式去執行,把值傳給他計算,算完後回來,就算值改變了也不會寫回去
> **CHANGING VALUE** 把值傳給他 ,跑著跑著再改寫值(不同位置,但回傳後更改其值)
> **CHANGING** 呼叫的時候傳同一個記憶體空間,變數改變之後,回來的值也會改變(相同記憶體位置)

實例 **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://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
第二屏幕显示完毕,结束处理。