邏輯數據庫提供了另外一種獲得數據的方式,它可以代替Open SQL語句從數據庫中讀取數據。LDB不是一種可以進行數據存儲的物理上的數據庫,而是ABAP報表程序設計中用到的一種事先定義好了的數據庫讀取程序。
可以通過以下兩種方式打開LDB編輯器:
l SE36、SLDB
可以通過LDB的GOTO菜單來在LDB的各組件之間進行切換:
創建新的LDB時,LDB的名稱一定要以Z或者Y打頭(其實其他用戶定制對象也一樣,如報表程序也需要Z或Y開頭),否則需要開發Key:
主要組成部分
LDB主要由三部分組成:.
結構(Structure)
決定了數據從哪些數據庫表、視圖中提取數據,以及這些表、視圖之間的層次關系(層次將決定數據讀取的順序)。LDB的節點類型有以下4種:
數據庫表(T類型節點):節點名稱(上圖中的根節點名稱輸入框)必須為數據庫表名(上圖中的數據庫表輸入框)或者view,且不可以為縱深結構。此類型(數據庫表或視圖)的節點情況下,可執行程序里,你可以使用NODES or TABLES語句來定義工作區,在LDB的數據庫程序中,需要對每個節點使用NODESor TABLES來定義,不能有TYPE選項。如果節點是非數據庫表,只能使用NODES來定義。
使用NODESor TABLES定義的工作區可以供數據庫程序與可執行程序(或LDB_PROCESS函數)共享數據,進行數據的傳輸。
詞典類型(S類型節點):數據字典中的定義的data type,詞典類型名(上圖中的詞典類型輸入框)與節點名稱(上圖中的根節點名稱輸入框)不需要一致,且可以為縱深結構。此類型節點情況下,可執行報表程序與LDB數據庫程序里都只能使用NODES語句來定義。
類型組(上圖中的數據類型,C類型節點):節點類型可以來自於類型組中定義的類型,其名稱必須為Type group字段值。一般應參照DDIC類型生成,以便其他使用邏輯數據庫的應用可以訪問該節點(如SAP Query)。此類型節點情況下,可執行報表程序與LDB數據庫程序里都只能使用NODES語句來定義。
動態類型(A類型節點):這種節點沒有固定類型,實際的類型是在可執行報表程序里通過NODES語句的TYPE選項來決定。在可執行程序里,必須使用NODES語句的TYPE選項來指定某個data type.
在程序里,可以使用
NODES node [TYPE type].
NODES的唯一作用就是在LDB與可執行程序之間傳遞數據。它定義了一個interface work area,並只能在報表程序的全局聲明區或者LDB數據庫程序中出現。
比如節點類型為S的節點:root_node,數據類型為INT4,LDB的數據庫程序的最TOP Include文件包括以下語句:
NODES root_node.
另外,在LDB數據庫程序包括了以下過程:
FORM put_root_node.
DO 10 TIMES.
root_node = sy-index.
PUT root_node.
ENDDO.
ENDFORM.
在與此LDB關連的可執行程序:
REPORT demo_nodes.
NODES root_node.
GET root_node.
WRITE root_node.
選擇(Selections)
定義了LDB的選擇屏幕,該選擇屏幕的布局由LDB的結構決定,一旦將LDB鏈接到報表程序后,該選擇屏幕會自動嵌入到默認選擇屏幕1000中。如果是通過函數LDB_PROCESS來調用LDB,則該選擇屏幕會以接口參數的形式出現在LDB_PROCESS函數中。
在LDB中,可以使用PARAMETERS, SELECT-OPTIONS; andSELECTION-SCREEN來定義選擇屏幕,在LDB中,還可以使用VALUE-REQUEST and HELPREQUEST語句。
三個數據庫表的層次結構:一個航線(SPFLI,如北京到新加坡)中可能有多個班次(SFLIGHT,如每天一班),每個班次中有多個訂票數據(SBOOK,機票預定信息),這個層次化的結構的處理方式與用傳統Open SQL的SELECT語句進行三個循環次的嵌套很相似:
第一次進入LDB選擇屏幕程序時,系統會為每個LDB生成一個名為DB<LDB_Name>SELInclude選擇屏幕的文件(注:此Include文件不需要在LDB數據庫程序中使用INCLUDE語句來包含它,系統會自動加載),生成的過程中需要選擇哪些表需要自動開啟動態選擇條件(dynamic selections)與字段選擇(field selections):
而且,所有表(T類型的節點)的主鍵都會出現在SELECT-OPTIONS語句中,成為屏幕選擇字段(自動生成的需要去掉注釋,並設置屏幕選擇字段名):
除了上面自動生成的LDB屏幕字段外,還可以使用以下面語句來擴展LDB選擇屏幕:
l 使用PARAMETERS語句為增加一個單值輸入條件框(PARAMETERS語句一般在LDB中只用於除節點表外的非表字段屏幕參數),在PARAMETERS語句中必須使用選項FOR NODE(所屬類型節點)或者FOR TABLE(T類型節點)
l 使用SELECTION-SCREEN語句來格式化屏幕
l SELECTION-SCREEN DYNAMIC SELECTIONS FOR NODE|TABLE <node>.語句允許你為更多的表開啟動態選擇條件功能。如果節點類型為T,可以使用TABLE來代替NODE。只有開啟了動態選擇條件功能的表,才可以在LDB數據庫程序中對表的進行動態選擇條件處理(具體請參考LDB_PROCESS函數EXPRESSIONS參數部分)
l SELECTION-SCREEN FIELD SELECTION FOR NODE|TABLE <node>.允許你為其他表開啟動態選擇字段。如果節點類型為T,可以使用TABLE來代替NODE。在報表程序中,可以通過GET語句中的fields選項來指定需要讀取的字段列表;在LDB_PROCESS函數中,可以通過FIELD_SELECTION參數來指定需讀取的字段列表(具體請參考LDB_PROCESS函數 FIELD_SELECTION參數部分)
l SELECTION-SCREEN BEGIN OF VERSION <dynnr>
...
SELECTION-SCREEN EXCLUDE <f>.
...
SELECTION-SCREEN BEGIN OF VERSION <dynnr>.
允許你創建不同的版本的LDB選擇屏幕,<dynnr>需要小於1000,你可以將<f> Selections或者Parameters屏幕字段隱藏,這樣可執行程序可以有不同版本的選擇屏幕。
假設有名為TEST_LDB的LDB,結構如下:
默認生成的Include選擇屏幕如下:
*-----------------------------------------------------------*
* Include DBTEST_LDBSEL
* 該Include文件會自動包括到LDB數據庫程序中去,不需要手動Include
* It will be automatically included into the database program
*-----------------------------------------------------------*
* 如果程序是自動生成的,請執行以下步驟:
* If the source is automatically generated,
* please perform the following steps:
* 用相應的字段名(最多8字符)替換問號
* 1. Replace ? by suitable names (at most 8 characters).
* 激活 SELECT-OPTIONS 與 PARAMETERS 語句(去除前面的注釋星號)
* 2. Activate SELECT-OPTIONS and PARAMETERS (delete stars).
* 保存修改后的源代碼
* 3. Save source code.
* 修改LDB數據庫程序
* 4. Edit database program.
*
* 提示:Include不能進行單獨的語法檢測!它將在LDB數據庫程序在執行
* 語法檢測時,一起進行語法檢測
* Hint: Syntax-Check is not possible within this Include!
* It will be checked during syntax-check of database program.
*-----------------------------------------------------------*
* SELECT-OPTIONS : ? FOR LFA1-LIFNR.
*
* 搜索幫助
* Parameter for search pattern selection (Type SY-LDB_SP):
* PARAMETERS p_sp AS SEARCH PATTERN FOR TABLE LFA1.
*
* SELECT-OPTIONS :
* ? FOR LFB1-LIFNR,
* ? FOR LFB1-BUKRS.
* SELECT-OPTIONS :
* ? FOR LFC1-LIFNR,
* ? FOR LFC1-BUKRS,
* ? FOR LFC1-GJAHR.
* SELECT-OPTIONS :
* ? FOR BKPF-BUKRS,
* ? FOR BKPF-BELNR,
* ? FOR BKPF-GJAHR.
*
* 開啟節點的動態選擇條件
* Enable DYNAMIC SELECTIONS for selected nodes :
* 開啟節點的動態字段選擇
* Enable FIELD SELECTION for selected nodes :
也可使用PARAMETERS為節點BKPF自定義選擇屏幕參數:
PARAMETERS PSTIDA LIKE SY-DATUM FOR NODE BKPF.
數據庫程序(Database program)
包含了具體的從數據庫表讀取的邏輯,以及將讀取的數據傳遞給LDB用戶的代碼。該程序是一系列子程序的集合,具體的結構取決於邏輯數據庫的結構和選擇(屏幕)。LDB中的其他元素包括了文檔、文本及用戶定義的選擇屏幕等。
名為<F1S>的LDB的數據庫程序名為SAPDB<F1S>,它包含了ABAP運行時調用的特定名稱的Form。當第一次打開LDB數據庫程序時,系統會自動生成LDB數據庫程序代碼
一個LDB程序一般包含以下這些FORM:
?FORM LDB_PROCESS_INIT
Called once only before the logical database is processed. It prepares it to be calledmore than once by the function module LDB_PROCESS.
在LDB處理前僅調用一次。通過函數方式訪問LDB時,可以調用多次???????
If you want to call a logical database more than once in succession, the database program must
contain the following subroutine:
FORM LDB_PROCESS_INIT CHANGING SUBRC LIKE SY-SUBRC.
...
SUBRC = 0.
ENDFORM.
此過程是LDB數據庫程序第一個被調用的FORM。一旦參數SUBRC設置為0,則LDB就會接着往處理數據,否則如果設置為0,則LDB_PROCESS函數會觸發LDB_NOT_REENTRANT異常。
This is the first subroutine to be called in the database program. Once the parameter SUBRC
has been set to 0, the logical database can perform the initialization routines required to allow it
to be called more than once. If the parameter SUBRC is not set to 0, the function module
LDB_PROCESS triggers the exception LDB_NOT_REENTRANT.
? FORM INIT
Called once only before the selection screen is processed.
在選擇屏幕處理前僅調用一次(在PBO之前調用)。
? FORM PBO
在選擇屏幕每次顯示之前調用,即LDB選擇屏幕的PBO事件塊。通常情況下,只有在可執行程序里使用LDB時才調用,在LDB_PROCESS 函數里不會調用。
? FORM PAI
用戶在選擇屏幕上輸入之后調用,即LDB選擇屏幕的PAI事件塊。只有在可執行程序里使用LDB時才調用,在LDB_PROCESS 函數里不會調用。
該FORM帶兩個接口參數FNAME and MARK將會傳到subroutine 中。FNAME存儲了選擇屏幕中用戶所選擇的選擇條件(SELECT-OPTION)與參數(PARAMETERS)的屏幕字段名,MARK標示了用戶選擇的是單值還是多值條件:MARK = SPACE意味着用戶輸入了一個簡單單值或者范圍取值,MARK = '*'意味着用戶在Multiple Selection screen 的輸入(即多個條件值)。MARK = SPACE means that the userhas entered a simple single value or range selection. MARK = '*' means that the user hasalso made entries on the Multiple Selection screen
聯合使用 FNAME = '*' 和 MARK = 'ANY', 表示所有的屏幕參數都已檢驗完成,即可以對屏幕整體參數做一個整體的檢測了(這里的意思應該就是相當於AT SELECTION-SCREEN)。
? FORM LDB_PROCESS_CHECK_SELECTIONS
用來在函數中LDB_PROCESS替代subroutine PAI,此過程可以對通過LDB_PROCESS函數參數接口傳遞進來的LDB屏幕選擇條件參數進行檢測
當通過LDB_PROCES函數來調用LDB時,LDB選擇屏幕是不會顯示的,這樣,LDB選擇屏幕參數就只能通過LDB_PROCES函數的接口參數傳遞到LDB數據庫程序中了,此是,LDB數據庫程序中的 FORM PAI 是不會再被執行(只在LDB與報表程序通過屬性綁定時才調用)。但時,如果此時你仍然想對通過LDB_PROCES函數接口參數傳遞進來的LDB選擇屏幕字段進行檢測時,你可以在LDB數據庫程序中定義如下的FORM:
FORM LDB_PROCESS_CHECK_SELECTIONS CHANGING SUBRC LIKE SY-SUBRC
MSG ..LIKE SYMSG.
...
SUBRC = ...
ENDFORM.
如果SUBRC不為0,則LDB_PROCESS函數會拋LDB_SELECTIONS_NOT_ACCEPTED異常。
? FORM PUT_<node>
最頂層節點<node>所對應的FORM PUT_<node>會在START-OF-SELECTION事件結束后自動被調用,而其他下層節點所對應的FORM會由它的上層節點所對應的FORM中的PUT <node>語句來觸發(在上層節點所對應的可執行程序中的相應GET事件塊執行之后觸發)。
PUT <node>.
此語句用是上面的PUT_<node>子過程中的特定語句,它是與PUT_<node>一起使用的,通常是放在循環處理數據循環過程中。LDB必須包含節點<node>,並且所對應的子過程名為PUT_<node>。PUT語句根據LDB的結構指引了報表程序的邏輯。該語句會觸發相應的ABAP報表程序的GET <node>事件。當GET事件塊執行完后,如果有下層節點,則還會調用下層節點所對應的FORM PUT_<node>。PUT語句是該Form(PUT_<node>)中最主要的語句:此語句僅僅只能在LDB數據庫程序的Form中使用。
當PUT_<node>調用結束后,報表程序中相應GET <node> LATE事件塊也會自動調用。
首先,LDB的子過程中根節點所對應的PUT_<root>會自動執行,此子過程中的PUT語句會以下面的先后順序來執行程序:
1、 如果LDB數據庫程序包含了AUTHORITY_CHECK_<table>語句,則PUT語句的第一件事就是調用它
2、 然后,PUT語句會觸發報表程序相應的GET事件,或者,去調用LDB_PROCESS的CALLBACK參數指定的函數
3、 再后,PUT語句會去調用LDB程序中下一節點的PUT_<node>子過程(此過程又會按照這里的三步來運行),直到下層所有子孫節點PUT_<node>過程處理完成,又會回到最上一層節點的PUT語句
4、 當控制權從下層節點的PUT_<node>返回時,PUT語句還會觸發當前節點的GET <node> LATE報表事件
?FORM AUTHORITY_CHECK_<node>
由PUT <node>語句自動調用。在該FORM中可以對數庫節點<node>權限進行檢查。
?FORM PUT_<ldb>_SP
Called when the user makes a selection using a search help to process the key chosenin the search help. <ldba> is the name of the logical database. From this subroutine, youcan use the entries in the search help tables to read the relevant entries from the rootnode <root>. The processing in the program can then be triggered using PUT <root>.The subroutine PUT_<root> is then not called automatically.
?FORM BEFORE_EVENT
在某個報表事件塊執行前調用,至於是哪個事件塊,可以由此FORM的參數EVENT來指定。目前,EVENT參數的值只能為START-OF-SELECTION:即在START-OF-SELECTION事件塊調用之前調用此FORM。
?FORM AFTER_EVENT
在某個報表事件塊執行后調用,至於是哪個事件塊,可以由此FORM的參數EVENT來指定。目前,EVENT參數的值只能為END-OF-SELECTION:即在END-OF-SELECTION事件塊調用之后調用此FORM。
?FORM <par>_VAL, <selop>_VAL, <selop>-LOW_VAL, <selop>-HIGH_VAL
調用用戶按F4(values help)時調用,<par>為LDB選擇屏幕的parameter,<selop>為LDB選擇屏幕的select-options參數。
?FORM <par>_HLP, <selop>_HLP, <selop>-LOW_HLP, <selop>-HIGH_HLP
調用用戶按F1(input help)時調用,<par>為LDB選擇屏幕的parameter,<selop>為LDB選擇屏幕的select-options參數。
LDB程序結構
自動生成的LDB數據庫程序的組織結構如下:
注:上圖中,每個FORM中的 PUT XXXX循環調用一次后立即調用下層節點的FORM PUT_XXX,而不是等到SELECT…ENDSELECT循環完后才去調用下層節點,而且是每一次整個鏈調用完后,再向上一層層返回,至到最頂層時,最頂層才算一次成功調用(此程序中使用了SELECT…ENDSELECT語句,這里只是個演示,在實行的應用中不會這么使用的)。
FORM PUT_XXX性能問題
一般自動生成的LDB數據庫程序中,用來訪問數據庫表的FORM都是使用SELECT…ENDSELECT來讀取語句,這樣性能低下,盡量避免使用此類語句,而是將數據一次性讀取到內表,則對該內表進行循環,再在循環中使用PUT XXX語句與報表程序進行交互:
FORM PUT_SBOOK.
SELECT * FROM SBOOK
INTO SBOOK....
PUT SBOOK.
ENDSELECT.
ENDFORM.
GET_EVENT內表
Some internal tables are automatically generated, and can be used in theprogram.
The internal table GET_EVENT contains the nodes of the logical database that are
requested by the user in GET statements. The table is generated as follows:
DATA: BEGIN OF GET_EVENTS OCCURS 10,
NODE(10),
KIND,
END OF GET_EVENTS.
Each line contains the name of a node of the logical database in the NODE field. The
KIND field specifies whether and how the node is requested by the user.
? KIND = 'X': Node is addressed in GET and GET LATE.
? KIND = 'G': Node is addressed only in GET.
? KIND = 'L': Node is addressed only in GET LATE.
? KIND = 'P': Node is addressed neither in GET nor in GET LATE. However, a
subordinate node is addressed in GET or GET LATE.
? KIND = ' ': Node is addressed neither in GET nor in GET LATE. No subordinate
node is addressed either.
報表程序的LDB事件
GET事件
從邏輯數據庫讀取數據主要使用GET事務
LDB節點訪問前需要在程序中使用NODES語句進行聲明:
NODES node.
在舊版本中也經常使用TABLES語句來聲明。在聲明后,系統將創建一個與該節點同名結構相同的工作區,並通過GET事件循環對該工作區進行填充:
GET事件塊會在LDB程序從數據庫表中讀取到一行數據時被觸發。
GET node [LATE] [FIELDS f1 f2 ...]
在事件觸發后,表工作區(node所定義的)存儲了剛讀到的數據,接着可以在GET事件塊中對讀取到當前行數據進行處理,數據庫中有多少條數據,GET事件塊就會相應執行多少次。使用FIELDS選項,可以指定從LDB讀取哪些表字段(但同時還必須讀取表關鍵字)。
GET LATE:當當前層次的Node的所有GET事件結束之后,並在返回鄰近上一層節點之前,則會觸發當前層次節點為的GET…LATE事件(僅執行一次,這與GET事件不一樣),因此,該事件可以實現該級數據庫節點中的數據統計功能。
出於性能問題考慮,使用FIELDS選擇指定需要的讀取的字段。
此外,如果在程序中沒有指定所有的邏輯節點,則執行到指定的最低一級節點后將返回上一級節點,其下方的所有節點中的數據將無法被讀出。
中止GET事件
更多事件終止請參考這里
STOP.
結束后續整個還沒有讀取的所有節點,並且觸發 END-OF-SELECTION 事件
EXIT.
退出所有的GET代碼塊,並且不觸發任何后續事件,直接轉向基礎列表屏幕(Basic List Screen)的輸出顯示。其功能與STOP基本一致,只是它不會觸發后事件
其中STOP語句和EXIT語句的用法與其他事件塊完全相同
REJECT.
中止當前GET事件並轉向邏輯數據同一層的下一個GET事件,即轉向數據庫中的下一行數據。
REJECT node_name.
中止當前和所有同一級別節點的所有后續GET事件,執行當前的高層次(即node_name所指層次)的下一個邏輯數據庫GET事件。
注:這里的node_name在LDB表的層次結構中,應該是位於當前GET事件中數據表的高層。
REJECT語句與上下無關,即使在循環和子程序中使用也一樣只是離開當前GET事件,而不是離開循環。
CHECK XXX
CHECK語句可以條件中止GET事件,之后系統將執行LDB同一層的下一行數據的GET事件,即讀取當前節點表的下一行數據。
除此之外,CHECK語句還有另一種使用方式,檢查當前行的內容是否滿足所有與該數據庫相連的選擇表中存儲的選擇標准(就是讀取一行數據后,與選擇屏幕中輸入的相應條件進行比較):
CHECK SELECT-OPTIONS
這種只用於GET事件塊內部,在用LDB讀入數據庫表的一行數據之后使用該語句,將檢查所有參照當前GET事件所對應的節點數據表中的選擇標准。並且一般只有當LDB提供的選擇不能滿足要求,並且相關表不具有動態選擇時才使用該形式。
使用LDB
邏輯數據庫可以用為 QuickViews、SAP Queries以及ABAP程序的數據源。
SAP Queries中,LDB可以直接作為數據源;在Query中,LDB通過在其基礎上定義的功能區域(functional area)成為間接數據源;
在可執行程序中,可以在通過程序的屬性項“Logical database”鏈接到LDB:
或者在ABAP程序中直接通過LDB_PROCESS函數來調用相應的LDB。如果通過程序屬性項“Logical database”鏈接到LDB,則在報表程序中可以通過LDB的GET事件來獲取數據。
當使用可執行程序的屬性與LDB綁定時,用戶可以在LDB選擇屏幕上輸入條件值。如果你采用函數的形式來調用LDB的話,LDB的選擇屏幕是不會顯示的,此時可以通過LDB_PROCESS函數的接口參數來來代替。
報表程序與LDB程序交互過程
在綁定了LDB的報表程序的執行順序如下:
1. 選擇屏幕處理以前初始化
先調用LDB程序中的過程:FORM INIT,該過程僅僅只在選擇屏幕第一次顯示之前被調用
再觸發報表程序中的事件:INITIALIZATION,該事件僅僅只在選擇屏幕第一次顯示之前被觸發
2. 每次選擇屏幕顯示之前屏幕初始化PBO
先調用LDB程序中的過程:FORM PBO,選擇屏幕每次顯示之前都會被調用
再觸發報表程序中的事件:AT SELECTION-SCREEN OUTPUT,選擇屏幕每次顯示之前都會被觸發
3. 顯示選擇屏幕,與用戶進行交互
4. 如果用戶按F4(values help)或者按下了字段幫助(F1)時
先調用LDB程序中的以下過程:
FORM <par>_VAL.
FORM <selop>_VAL.
FORM <selop>-LOW_VAL.
FORM <selop>-HIGH_VAL.
以上是按F4時調用,其中<par>為LDB選擇屏幕的parameter,<selop>為LDB選擇屏幕的select-options參數
如果是按F1時,將上面的 _VAL 換成_HLP即是被調用的過程
再觸發選擇屏幕事件:
AT SELECTION-SCREEN ON VALUE-REQUEST FOR <par>.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR <selop>-LOW.
AT SELECTION-SCREEN ON VALUE-REQUEST FOR <selop>-HIGH.
以上是按F4時調用,其中<par>為LDB選擇屏幕的parameter,<selop>為LDB選擇屏幕的select-options參數
如果是按F1時,將上面的VALUE-REQUEST換成HELP-REQUEST即是被觸發的屏幕事件
5. 選擇屏幕的PAI事件。檢查用戶的輸入是否正確,如果輸入數據不正確,可以提示用戶,並要求再次重新輸入相關字段。
此時先調用LDB程序中的過程:FORM PAI USING FNAME MARK.
FNAME代表選擇屏幕參數字段名。如果MARK=SPACE,表示用戶輸入是一個單值或者是一個范圍;如果MARK=*,則表示用戶輸入了多行值。
Using the combination FNAME = '*' and MARK = 'ANY', you can check all entries at
once when the user chooses a function or presses ENTER.聯合使用 FNAME = '*' 和 MARK = 'ANY', 則可以在用戶選擇“執行”后立即檢查所有條目(這里的意思應該就是相當於AT SELECTION-SCREEN)。
再觸發選擇屏幕事件:
AT SELECTION-SCREEN ON <fname>.
針對於選擇屏幕某字段輸入的PAI事件(ON事件表示當對應字段的值被傳遞給程序時被觸發)
AT SELECTION-SCREEN ON END OF <fname>.
這個事件只能使用SELECT-OPTIONS屏幕參數上,用於整個選擇表輸入結束后對整個輸入的選擇條件列表進行檢查。.
AT SELECTION-SCREEN.
選擇屏幕的基本PAI事件,所有用戶輸入的數據都被傳輸到程序中之后才觸發,也是選擇屏幕中最后被觸發的事件
6. 數據讀取前的處理
此時先調用LDB程序中的過程:BEFORE EVENT 'START-OF-SELECTION',可以通過此過程,在讀取數據前做一些運動作,如初始化內表
再觸發報表程序事件:START-OF-SELECTION,這是報表程序的在選擇屏幕處理結束后執行的第一個事件。可以在此事件塊中為數據的處理做一些准備
7. 從LDB中讀取數據,並在可執行程序進行數據處理
此時先調用LDB程序中的過程:FORM PUT_<node>,從節點<node>中讀取數據
當<node>及子孫節點所對應的PUT_XXX執行完后,再觸發報表程序事件:GET <node> [LATE],此過程中可以對數據做階段型處理,這有點像LOOP循環中的SUM
8. 數據讀取后的處理
此時先調用LDB程序中的過程:AFTER EVENT 'END-OF-SELECTION',可以通過此過程,在讀取數據后做一些動作,如釋放內存
再觸發報表程序事件:END-OF-SELECTION,這是最后一個報表事件
9. 如果在上面一些步驟中生成了LIST,則程序會交給list processor,並顯示LIST
LDB選擇屏幕字段的顯示與否
在報表選擇屏幕上是否顯示LDB的普通選擇條件(即靜態的,與動態選擇條件相對應),則要看報表程序中是否使用了對應的
TABLE <node>語句,如果有,則與<node>節點相關的所有LDB選擇條件都會顯示在報表程序的選擇屏幕上,如果沒有此語句,則與<node>節點相關的所有LDB選擇條件都會不會顯示(但如果某個節點沒有在TABLE語句中進行定義,但其子節點,或子孫節點在TABLE語句中進行了定義,則這些子孫節點所對應的父節點所對應LDB屏幕選擇條件還是會嵌入到報表選擇屏幕中)。有幾種情況:
則報表程序的選擇屏幕只會將spfli節點相關的普通選擇條件內嵌進來,子孫節點不會顯示出來:
則報表程序的選擇屏幕中,會將sbook的父節點SFLIGHT以及爺節點SPFLI相關的LDB靜態選擇內嵌進來:
如果LDB的選擇屏幕在沒有創建選擇視圖的情況下:動態選擇是否顯示在報表程序的選擇屏幕中,首先要看報表程序中是否使用了 TABLE <node>對需要動態顯示的節點進行了定義(如果這個節點是上層節點,則此節點為本身也可以不在TABLE語句定義,而是對其子孫節點進行定義也是可以的),再者,還需要相應的<node>節點在LDB屏幕選擇Include程序中的SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE <node>語句中進行定義,注:要顯示,則對應節點一定要在此語句中定義過,而不是像報表程序中的節點只對其子孫節點進行定義即可,而是誰需要動態顯示,則誰就得要在動態定義語句中進行定義,如下面在LDB選擇屏幕Include程序中只對SBOOK的上層節點SPFLI,SFLIGHT進行了定義,並沒有對SBOOK進行定義:
而在報表程序中只能SBOOK進行了定義:
但最后在報表動態選擇屏幕中,只有SPFLI,SFLIGHT兩個表的條件(需使用SELECTION-SCREEN DYNAMIC SELECTIONS語句對SPFLI,SFLIGHT節點進行定義),而SBOOK並沒有:
在沒有創建選擇視圖的情況下,以表名來建小分類,且動態條件字段為整個表的所有字段
如果LDB的選擇屏幕在有選擇視圖的情況下:只要存在選擇視圖,則只顯示選擇視圖里被選擇的字段,其他任何字段一概不顯示。
下面只將SPFLI-CARRID與SFLIGHT-CONNID兩個字段已分別納入到了01與02分組中,而SBOOK節點中沒有字段納入:
報表程序里將SBOOK節點定義在了TABLES語句中,所以,從SBOOK這一級開始(包括)向上所有節點的所對應的字段,如果納入了選擇視圖中,則選擇屏幕顯示如下:
LDB中的權限檢查
可以在報表程序相應事件塊或者是LDB數據庫程序的相應子過程中,通過AUTHORITY-CHECK語句來對LDB進行權限檢查:
LDB程序的子過程中:
? PAI
? AUTHORITY_CHECK_<table>
報表程序事件中:
? AT SELECTION-SCREEN
? AT SELECTION-SCREEN ON <fname>
? AT SELECTION-SCREEN ON END OF <fname>
? GET <table>
通過LDB_PROCESS函數訪問LDB
Calling a Logical Database Using a Function Module
可以將LDB當做Function來調用。通過函數訪問LDB,可以在同一程序中訪問多個LDB,也有可能在同一程序中對同一個LDB進行多次調用。在4.5A版以前,如果一個報表程序需要訪問多個LDB,或多次訪問同一LDB時時,只能在這個報表程序里通過SUBMIT語句來調用另一個報表程序,且被SUBMIT語句調用的報表程序與其它LDB進行了綁定,數據只能通過ABAP memory將數據傳回到主調程序中。
如果你采用函數的形式來調用LDB的話,LDB的選擇屏幕是不會顯示的,但是你可以通過LDB_PROCESS函數的接口參數來給LDB選擇屏幕條件字段賦值。此時LDB不會觸發主調程序中的GET事件,但數據可以通過LDB_PROCESS函數參數接口中指定的回調函數傳回。
如果不是在同一報表程序中調對某個LDB多次進行調用時,就沒有必要采用LDB_PROCESS函數訪問LDB。
采用函數訪問LDB時,LDB數據庫程序中的PAI子過程是不會被調用的,所以不會對LDB選擇屏幕條件進行檢查,但可以通過后面講解的LDB數據庫程序中的LDB_PROCESS_INIT、LDB_PROCESS_CHECK_SELECTIONS函數來檢驗
通過函數LDB_PROCESS訪問LDB時,LDB數據庫程序的子過程會按以下先后順序來執行:
1. LDB_PROCESS_INIT
2. INIT
3. LDB_PROCESS_CHECK_SELECTIONS
4. PUT <node>.
LDB_PROCESS函數的參數
import parameters
? LDBNAME
你想調用的LDB名稱
? VARIANT
變式名
Name of a variant to fill the selection screen of the logical database. The variant must
already be assigned to the database program of the logical database. The data is passed
in the same way as when you use the WITH SELECTION-TABLE addition in a SUBMIT
[Page 1060] statement.
?EXPRESSIONS SQL動態選擇條件(參考《User Dialogs.docx》中的 Calling Programs——WITH FREE SELECTION <freesel>章節)
In this parameter, you can pass extra selections for the nodes of the logical database for
which dynamic selections are allowed. The data type of the parameter RSDS_TEXPR is
defined in the type group RSDS. The data is passed in the same way as when you use
the WITH FREE SELECTION addition in a SUBMIT statement.
由於采用調用函數LDB_PROCESS的方式來調用LDB時,LDB的選擇屏幕(以及LDB動態選擇屏幕)是不會的,但如果此時想在查詢某個節點時,其Where從句后要使用動態的內表條件時,就需要在主調程序中使用此參數來傳遞節點(表)的動態選擇條件字段。在主調程序中,首先使用以下語句來定義動態條件內表texpr:
TYPE-POOLS: rsds.
DATA: texpr TYPE rsds_texpr."rsds_texpr為類型組RSDS中定義的內表類型
然后,在主調程序中按照以下行結構類型來初始化動態條件內表texpr:
(其中主調程序中用到的類型組RSDS源碼如下:)
最后,在主調程序中調用LDB_PROCESS函數時,通過其入參數EXPRESSIONS將動態條件內表texpr傳遞到LDB數據庫程序中,然后LDB數據庫程序中相應節點(表)的Form PUT_XXX 中讀取數據時,就可以使用此動態條件內表作為Where從句中的條件了(注:如果動態內表為空,則會忽略此條件,查找所有記錄):
上面LDB數據庫程序中的RSDS_WHERE條件內表來自RSDS類型組,相應源碼如下:
(另外,上面LDB數據庫程序中要能從DYN_SEL-CLAUSES內表讀取數據,則必須在LDB選擇屏幕里開啟相應節點的動態選擇條件:)
其中,DYN_SEL-CLAUSES內表行結構如下:
?FIELD_SELECTION SQL動態選擇字段
You can use this parameter to pass a list of the required fields for the nodes of the logical
database for which dynamic selections are allowed. The data type of the parameter is
the deep internal table RSFS_FIELDS, defined in the type group RSFS. The component
TABLENAME contains the name of the node and the deep component FIELDS contains
the names of the fields that you want to read.
為了從數據庫表中讀取數據時,只讀取有用的字段,則使用此參數來進行設定,些功能與GET事件中的FIELDS選項功能相同(均是讀取部分數據庫表字段,而不是將所有字段數據讀取):GET node [LATE] [FIELDSf1 f2 ...]
在主調程序中,首先使用以下語句來定義動態字段內表 fsel :
TYPE-POOLS: rsfs.
DATA: fsel TYPE rsfs_fields."rsfs_fields為類型組RSFS中定義的內表類型
(rsfs_fields內表類型所在RSFS內類組源碼如下:)
最后,在主調程序中調用LDB_PROCESS函數時,通過其入參數FIELD_SELECTION將動態字段內表fsel傳遞到LDB數據庫程序中,然后LDB數據庫程序中相應節點(表)的FORM PUT_XXX 中讀取數據時,就可以使用此動態字段內表作為Select從句中的字段選擇了(注:如果動態內表為空,則會忽略此條件,查找查詢所有字段):
(另外,上面LDB數據庫程序中要能從SELECT_FIELDS內表讀取數據,則必須在LDB選擇屏幕里開啟相應節點的動態選擇字段:)
內表parameters
?CALLBACK
You use this parameter to assign callback routines to the names of nodes and events.
The parameter determines the nodes of the logical database for which data is read, and
when the data is passed back to the program and in which callback routine.
CALLBACK為行類型為LDBCB結構類型的內表
LDBNOE:需要讀取的LDB節點名
GET:如果為 X ,則使用LDB_PROCESS函數方式調用LDB時,也可以具有好比可執行報表程序屬性綁定LDB方式情況下的GET事件,會調用CB_FORM參數指定的FORM
GET_LATE:如果為 X ,則使用LDB_PROCESS函數方式調用LDB時,也可以具有好比可執行報表程序屬性綁定LDB方式情況下的GET LATE事件,會調用CB_FORM參數指定的FORM
CB_PROG:CB_FORM參數指定的回調過程所屬程序名
CB_FORM:回調的Form過程
如果你給CALLBACK參數傳了個內表,則對於每個節點行數據,只少GET或GET_LATEe有一個值為X,或者兩個都可以為X
回調的過程必須具有以下方法簽名:
FORM <subr> USING <node> LIKE LDBCB-LDBNODE
<wa> [TYPE <t>]
<evt>
<check>.
這些參數會被LDB_PROCESS函數自動傳遞過來,各參數的意義如下:
<node>:節點名稱
<wa>:節點內表所對應的工作區。在主調程序以及該過程所在的程序不必要使用NODES or TABLES來聲明工作區。如是該過程
只是用來處理某一個節點時,你可以使用TYPE選項來為<wa>工作區指定具體類型,此類型即為某節點所對應的數據詞典類型。如果該過程要處理多個節點數據,則不要使用TYPE選項,此時需要通過 field symbol 來讀取工作區各組件字段的值。
<evt>:值為G or L,分別表示該過程是由GET與GET LATE事件觸發調用的。
<check>:
The callback routine (in <evt> 'G' only) can influence further processing. When the routine starts, the parameter contains the value 'X'. If it has the value SPACE at the end of the routine, the system interprets this as a sign that the callback routine has discarded the data record. As a result, none of the subordinate nodes are processed. This can lead to a considerable performance gain. Furthermore, it means that the checks do not have to be repeated for the subordinate nodes. Resetting <check> to SPACE is the equivalent of a negative CHECK in th e GET event.
?SELECTIONS
通過此參數可以給LDB的選擇屏幕字段傳遞值。其數據類型為行結構為RSPARAMS的內表,與SUBMIT語句中的WITH SELECTION-TABLE選項用法一樣
SELECTIONS and EXPRESSIONS 選項中的值會覆蓋VARIANT選項中同名字段
LDB程序中的Dynamic Selections
SELECTION-SCREEN DYNAMIC SELECTIONS FOR NODE|TABLE <node>.語句用在LDB屏幕選擇Include文件中,用來開啟<node>節點的LDB dynamic selections功能,即可以在WHERE從句中使用動態選擇條件(形如:…WHERE field1 = value1 AND (條件內表) …)
在PUT_<node> Form中的SELECT語句中使用dynamic selections,需要用到數據對象DYN_SEL,該數據對象是在LDB數據庫程序中自動生成的,其類型如下(不必在LDB程序中加入下面代碼行就可以直接使用DYN_SEL):
TYPE-POOLS RSDS.
DATA DYN_SEL TYPE RSDS_TYPE.
你不必在程序中定義它就可以直接使用,但它只能在LDB數據庫程序中使用,而不能用在報表程序中。RSDS_TYPE數據類型是在類型組RSDS中定義的:
TYPE-POOL RSDS .
* Type definitions for FREE SELECTIONS
* WHERE-clauses ------------------------------------------------------ *
TYPES: RSDS_WHERE_TAB LIKE RSDSWHERE OCCURS 5. RSDSWHERE 的類型為C(72)
TYPES: BEGIN OF RSDS_WHERE,
TABLENAME LIKE RSDSTABS-PRIM_TAB, RSDSTABS-PRIM_TAB類型為C(30)
WHERE_TAB TYPE RSDS_WHERE_TAB,
END OF RSDS_WHERE.
TYPES: RSDS_TWHERE TYPE RSDS_WHERE OCCURS 5.
* Expressions Polish notation ---------------------------------------- *
TYPES: RSDS_EXPR_TAB LIKE RSDSEXPR OCCURS 10.
TYPES: BEGIN OF RSDS_EXPR,
TABLENAME LIKE RSDSTABS-PRIM_TAB,
EXPR_TAB TYPE RSDS_EXPR_TAB,
END OF RSDS_EXPR.
TYPES: RSDS_TEXPR TYPE RSDS_EXPR OCCURS 10.
* Selections as RANGES-tables ---------------------------------------- *
TYPES: RSDS_SELOPT_T LIKE RSDSSELOPT OCCURS 10.
TYPES: BEGIN OF RSDS_FRANGE,
FIELDNAME LIKE RSDSTABS-PRIM_FNAME,RSDSTABS-PRIM_FNAME類型為C(30)
SELOPT_T TYPE RSDS_SELOPT_T,
END OF RSDS_FRANGE.
TYPES: RSDS_FRANGE_T TYPE RSDS_FRANGE OCCURS 10.
TYPES: BEGIN OF RSDS_RANGE,
TABLENAME LIKE RSDSTABS-PRIM_TAB,
FRANGE_T TYPE RSDS_FRANGE_T,
END OF RSDS_RANGE.
TYPES: RSDS_TRANGE TYPE RSDS_RANGE OCCURS 10.
TYPES: BEGIN OF RSDS_TYPE,
CLAUSES TYPE RSDS_TWHERE,
TEXPR TYPE RSDS_TEXPR,
TRANGE TYPE RSDS_TRANGE,
END OF RSDS_TYPE.
RSDS_TYPE是一個深層結構的結構體:
字段CLAUSES
Where從句部分,實則存儲了可直接用在WHERE從句中的動態Where條件內表,可以在Where動態語句中直接使用,該組件為內表,存儲了用戶在選擇屏幕上選擇的LDB動態選擇字段
每個被選擇的LDB屏幕動態選擇字段都會形成一個條件,並存儲到RSDS_TYPE-CLAUSES-WHERE_TAB內表中WHERE_TAB內表中存儲的就是直接可以用在Where從句中的動態選擇條件中。
每個表(節點)都會有自己的CLAUSES-WHERE_TAB動態條件內表,這是通過CLAUSES-TABLENAME來區別的。
現假設有名為 ZHK 的LDB,SCARR為該LDB的根節點,且僅有SPFLI一個子節點。LDB選擇屏幕 Include文件 DBZHKSEL內容如下:
SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.
"需要先開始動態選擇條件功能
SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE SCARR.
LDB數據庫程序SAPDBZHK中,PUT_SCARR過程中使用dynamic selection的過程如下:
FORM PUT_SCARR.
STATICS: DYNAMIC_SELECTIONS TYPE RSDS_WHERE,FLAG_READ.定義成靜態類型的是防止再次進入此Form時,再次初始化DYNAMIC_SELECTIONS結構,即只執行一次初始化代碼
IF FLAG_READ = SPACE.
DYNAMIC_SELECTIONS-TABLENAME = 'SCARR'.
READ TABLE DYN_SEL-CLAUSES WITH KEY DYNAMIC_SELECTIONS-TABLENAME INTO DYNAMIC_SELECTIONS.
FLAG_READ = 'X'.
ENDIF.
SELECT * FROM SCARR WHERE CARRID IN S_CARRID AND (DYNAMIC_SELECTIONS-WHERE_TAB).使用動態Where條件
PUT SCARR.
ENDSELECT.
ENDFORM.
字段TEXPR
TEXPR contains the selections of the dynamic selections in an internal format (Polish
notation).You can use this format with function modules FREE_SELECTIONS_INIT and
FREE_SELECTIONS_DIALOG in order to work with dynamic selections within a program (for
more information, see the documentation of these function modules).
字段TRANGE
該字段是一個內表,存儲了CLAUSES的原數據,CLAUSES內表里的數據實質就是來源於TEXPR內表,只是CLAUSES已經將每個表字段的條件拼接成了一個或多個條件串了(形如:“XXX字段 = XXX條件”),但是TEXPR內表與RANGES tables相同,存儲的是字段最原始的條件值,使用時,在WHERE 從句中使用 IN 關鍵字來使用這些條件值(這與SELECT-OPTIONS類型的屏幕參數用戶是完全一樣的)。
但是,使用TEXPR沒有直接使用CLAUSES靈活,因為使用TEXPR時,WHERE從句里的條件表字段需要事先寫好,這實質上不是動態條件了,可以參考以下實例,與上面CLAUSES用法相比就更清楚了:
現假設有名為 ZHK 的LDB,SCARR為該LDB的根節點,且僅有SPFLI一個子節點。LDB選擇屏幕 Include文件 DBZHKSEL內容如下:
SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.
"需要先開始動態選擇條件功能
SELECTION-SCREEN DYNAMIC SELECTIONS FOR TABLE SCARR.
LDB數據庫程序SAPDBZHK中,PUT_SCARR過程中使用dynamic selection的過程如下:
FORM PUT_SCARR.
STATICS: DYNAMIC_RANGES TYPE RSDS_RANGE, "存儲某個表的所有屏幕字段的Ranges
DYNAMIC_RANGE1 TYPE RSDS_FRANGE,"存儲某個屏幕字段的Ranges
DYNAMIC_RANGE2 TYPE RSDS_FRANGE,
FLAG_READ."確保DYN_SEL只讀取一次
IF FLAG_READ = SPACE.
DYNAMIC_RANGES-TABLENAME = 'SCARR'.
"先取出 SCARR 表的所有屏幕字段的Ranges
READ TABLE DYN_SEL-TRANGE WITH KEY DYNAMIC_RANGES-TABLENAME
INTO DYNAMIC_RANGES.
"再讀取出屬於某個字段的Ranges
DYNAMIC_RANGE1-FIELDNAME = 'CARRNAME'.
READ TABLE DYNAMIC_RANGES-FRANGE_T WITH KEY DYNAMIC_RANGE1-FIELDNAME
INTO DYNAMIC_RANGE1.
DYNAMIC_RANGE2-FIELDNAME = 'CURRCODE'.
READ TABLE DYNAMIC_RANGES-FRANGE_T WITH KEY DYNAMIC_RANGE2-FIELDNAME
INTO DYNAMIC_RANGE2.
FLAG_READ = 'X'.
ENDIF.
SELECT * FROM SCARR
WHERE CARRID IN S_CARRID
AND CARRNAME IN DYNAMIC_RANGE1-SELOPT_T"使用IN 關鍵字使用Ranges內表
AND CURRCODE IN DYNAMIC_RANGE2-SELOPT_T."(與select-options屏幕參數是一樣的用法)
PUT SCARR.
ENDSELECT.
ENDFORM.
更多詳情的可以參考LDB_PROCESS函數的EXPRESSIONS參數
LDB程序中的Field Selections
SELECTION-SCREEN FIELD SELECTION FOR NODE|TABLE <node>.語句的作用是開啟節點<node>的動態字段選擇的功能(形如: SELECT (選擇字段內表) FROM…,而不是 SELECT * FROM …,即選擇了哪些字段,就只查詢哪些字段,而不是將所有字段查詢出來,進而可以提高性能)。
在可執行報表程序里,可以通過GET node [FIELDS f1 f2 ...]語句中的 FIELDS選項來指定要讀取字段;
如果是通過LDB_PROCESS函數來調用LDB時,可以通過其參數FIELD_SELECTION來指定要讀取的字段,並且在LDB數據庫程序中,通過從SELECT_FIELDS內表中就可以讀取這些傳遞進來的選擇字段,SELECT_FIELDS是LDB數據庫程序自動生成的,其類型如下(不必在LDB程序中加入下面代碼行,直接就可以使用SELECT_FIELDS內表,另外在相連的報表程序中也可以使用,這與DYN_SEL不同):
TYPE-POOLS RSFS.
DATA SELECT_FIELDS TYPE RSFS_FIELDS.
RSDS_FIELDS中的FIELDS里存儲的就是GET…FIELDS…語句或者是FIELD_SELECTION參數傳遞過來的用戶指定的查詢字段,FIELDS內表可以直接使用在 SELECT…從句中。
現假設有名為 ZHK 的LDB,SCARR為該LDB的根節點,且僅有SPFLI一個子節點。LDB選擇屏幕 Include文件 DBZHKSEL內容如下:
SELECT-OPTIONS S_CARRID FOR SCARR-CARRID.
SELECT-OPTIONS S_CONNID FOR SPFLI-CONNID.
"需要先開始動態選擇字段功能
SELECTION-SCREEN FIELD SELECTION FOR TABLE SPFLI.
LDB數據庫程序SAPDBZHK中,PUT_SCARR過程中使用dynamic selection的過程如下:
FORM PUT_SPFLI.
STATICS: FIELDLISTS TYPE RSFS_TAB_FIELDS,
FLAG_READ."確保SELECT_FIELDS只讀取一次
IF FLAG_READ = SPACE.
FIELDLISTS-TABLENAME = 'SPFLI'.
"讀取相應表的動態選擇字段
READ TABLE SELECT_FIELDS WITH KEY FIELDLISTS-TABLENAME INTO FIELDLISTS.
FLAG_READ = 'X'.
ENDIF.
SELECT (FIELDLISTS-FIELDS)"動態選擇
INTO CORRESPONDING FIELDS OF SPFLI FROM SPFLI
WHERE CARRID = SCARR-CARRID
AND CONNID IN S_CONNID.
PUT SPFLI.
ENDSELECT.
ENDFORM.
在相應的可執行報表程序里,相應的代碼可能會是這樣的:
TABLES SPFLI.
GET SPFLI FIELDS CITYFROM CITYTO.
...
GET語句中的FIELDS選項指定了除主鍵外需要查詢來的字段,主鍵不管是否選擇都會被從數據庫表中讀取出來,可以由下面報表程序中的代碼來證明:
DATA: ITAB LIKE SELECT_FIELDS,
ITAB_L LIKE LINE OF ITAB,
JTAB LIKE ITAB_L-FIELDS,
JTAB_L LIKE LINE OF JTAB.
START-OF-SELECTION.
ITAB = SELECT_FIELDS.
LOOP AT ITAB INTO ITAB_L.
IF ITAB_L-TABLENAME = 'SPFLI'.
JTAB = ITAB_L-FIELDS.
LOOP AT JTAB INTO JTAB_L.
WRITE / JTAB_L.
ENDLOOP.
ENDIF.
ENDLOOP.
如果報表程序中的GET語句是這樣的:GET SPFLI FIELDS CITYFROM CITYTO.,則輸入結果為:
CITYTO
CITYFROM
MANDT
CARRID
CONNID
可以從輸出結果看出,主鍵MANDT、CARRID、CONNID會自動的加入到SELECT_FIELDS內表中,一並會從數據庫中讀取出來
LDB程序中的Search Help
PARAMETERS <p> AS SEARCH PATTERN FOR TABLE <node>
已過時,新創建的LDB不再建議使用