LDB不常用,但學好它可以寫出共用封裝好的查詢
6. 邏輯數據庫
6.1. 組成
SLDB
6.2. 結構
決定了數據從哪些數據庫表、視圖中提取數據,以及這些表、視圖之間的層次關系(層次將決定數據讀取的順序)
數據庫表(T類型節點)、詞典類型(S類型節點),比如節點類型為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."會去調用報表程序中的 GET root_node. 事件塊
ENDDO.
ENDFORM.
在與此LDB關連的可執行程序:
REPORT demo_nodes.
NODES root_node.
GET root_node.
WRITE root_node.
6.3. 選擇屏幕(Selections)
定義了LDB的選擇屏幕,該選擇屏幕的布局由LDB的結構決定,一旦將LDB鏈接到報表程序后,該選擇屏幕會自動嵌入到默認選擇屏幕1000中
第一次進入選擇屏幕程序時,系統會為每個LDB生成一個名為DB<LDB_Name>SELInclude選擇屏幕包含文件:
而且,所有表(T類型的節點)的主鍵都會出現在SELECT-OPTIONS語句中,成為屏幕選擇字段(自動生成的需要去掉注釋,並設置屏幕選擇字段名):
除了上面自動生成的LDB屏幕字段外,還可以使用以下面語句來擴展LDB選擇屏幕:
6.3.1. PARAMETERS屏幕參數擴充
增加一個單值輸入條件框(PARAMETERS語句一般在LDB中只用於除節點表外的非表字段屏幕參數),在PARAMETERS語句中必須使用選項FOR NODE XXX 或者 FOR TABLE XXX 來指定這些擴展參數屬性哪個節點的:PARAMETERS CITYTO LIKE SPFLI-CITYTO FOR NODE SPFLI.
注:SELECT-OPTIONS沒有FOR NODE這樣的用法
具體請參數后面的LDB選擇屏幕章節
6.3.2. SELECTION-SCREEN格式化屏幕
使用SELECTION-SCREEN語句來格式化屏幕
具體請參數后面的LDB選擇屏幕章節
6.3.3. DYNAMIC SELECTIONS動態選擇條件
SELECTION-SCREEN DYNAMIC SELECTIONS FOR NODE|TABLE <node>.用來開啟<node>節點的LDB dynamic selections功能,即可以在WHERE從句中使用動態選擇條件(形如:…WHERE field1 = value1 AND (條件內表) …只有開啟了動態選擇條件功能的表,才可以在LDB數據庫程序中對表進行動態選擇條件處理。下面是數據庫程序中如何使用動態選擇條件示例:
上面LDB數據庫程序中的RSDS_WHERE條件內表來自RSDS類型組,相應源碼如下:
另外,上面LDB數據庫程序中要能從DYN_SEL-CLAUSES內表讀取數據,則必須在LDB選擇屏幕里開啟相應節點的動態選擇條件:
其中,DYN_SEL-CLAUSES內表行結構如下:
6.3.3.1. DYN_SEL
PUT_<node> Form中的SELECT語句中Where從句如果要使用 DYNAMIC SELECTIONS 動態選擇條件時,需要用到變量DYN_SEL,該數據對象是在LDB數據庫程序中自動生成的,其類型如下(注:不必在LDB程序中加入下面代碼行就可以直接使用DYN_SEL):
TYPE-POOLS RSDS.
DATA DYN_SEL TYPE RSDS_TYPE.
你不必在程序中定義它就可以直接使用,但它只能在LDB數據庫程序中使用,而不能用在報表程序中。RSDS_TYPE數據類型是在類型組RSDS中定義的:
TYPE-POOL RSDS .
TYPES: RSDS_WHERE_TAB LIKE RSDSWHERE OCCURS 5."RSDSWHERE 類型為C(72)
TYPES: BEGIN OF RSDS_WHERE,
TABLENAME LIKE RSDSTABS-PRIM_TAB,
WHERE_TAB TYPE RSDS_WHERE_TAB,
END OF RSDS_WHERE.
TYPES: RSDS_TWHERE TYPE RSDS_WHERE OCCURS 5.
TYPES: BEGIN OF RSDS_TYPE,
CLAUSES TYPE RSDS_TWHERE,
TEXPR TYPE RSDS_TEXPR,
TRANGE TYPE RSDS_TRANGE,
END OF RSDS_TYPE.
RSDS_TYPE是一個深層結構的結構體,里面三個字段都是內表類型,其中以下兩個字段重要:
6.3.3.1.1. 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.
6.3.3.1.2. RSDS_TYPE-TRANGE
該字段是一個內表,存儲了CLAUSES的原數據,CLAUSES內表里的數據實質就是來源於TRANGE內表,只是CLAUSES已經將每個表字段的條件拼接成了一個或多個條件串了(形如:“XXX字段 = XXX條件”),但是TRANGE內表與RANGES tables相同,存儲的是字段最原始的條件值,使用時,在WHERE從句中使用 IN 關鍵字來使用這些條件值(這與SELECT-OPTIONS類型的屏幕參數用戶是完全一樣的)。
但是,使用TRANGE沒有直接使用CLAUSES靈活,因為使用TRANGE時,WHERE從句里的條件表字段需要事先寫好,這實質上不是動態條件了,可以參考以下實例,與上面CLAUSES用法相比就更清楚了:現修改上面的示例:
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.
6.3.4. FIELD SELECTION動態選擇字段
SELECTION-SCREEN FIELD SELECTION FOR NODE|TABLE <node>.語句的作用是開啟節點<node>的動態字段選擇的功能(形如:SELECT (選擇字段內表) FROM…,而不是SELECT * FROM …,即選擇了哪些字段,就只查詢哪些字段,而不是將所有字段查詢出來,進而可以提高性能)。
在可執行報表程序里,可以通過GET node [FIELDS f1 f2 ...] 語句中的 FIELDS選項來指定要讀取字段;
另外,上面LDB數據庫程序中要能從SELECT_FIELDS內表讀取數據,則必須在LDB選擇屏幕里開啟相應節點的動態選擇字段:
其中,SELECT_FIELDS內表行結構如下:
6.3.4.1. SELECT_FIELDS
PUT_<node> Form中的SELECT語句中Where從句如果要使用 FIELD SELECTION 動態選擇字段時,需要用到數據對象SELECT_FIELDS,在LDB數據庫程序中,通過從SELECT_FIELDS內表中就可以讀取GET node [FIELDS f1 f2 ...] 語句傳遞進來的選擇字段,SELECT_FIELDS是LDB數據庫程序自動生成的,其類型如下(不必在LDB程序中加入下面代碼行,直接就可以使用SELECT_FIELDS內表,另外在相連的報表程序中也可以使用,這與DYN_SEL不同):
TYPE-POOLS RSFS.
DATA SELECT_FIELDS TYPE RSFS_FIELDS.
RSDS_FIELDS中的FIELDS里存儲的就是GET…FIELDS…語句傳遞過來的用戶指定的查詢字段,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. "在報表程序中也可以直接使用LDB程序中的全局變量!
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內表中,一並會從數據庫中讀取出來
6.4. 數據庫程序中重要FORM
? FORM INIT
在選擇屏幕處理前僅調用一次(在PBO之前調用)
? FORM PBO
在選擇屏幕每次顯示之前調用,即LDB選擇屏幕的PBO事件塊
? FORM PAI
用戶在選擇屏幕上輸入之后調用,即LDB選擇屏幕的PAI事件塊(之后?)。
該FORM帶兩個接口參數FNAME and MARK將會傳到subroutine 中。FNAME存儲了選擇屏幕中用戶所選擇SELECT-OPTION與PARAMETERS的屏幕字段名,MARK標示了用戶選擇的是單值還是多值條件:MARK = SPACE意味着用戶輸入了一個簡單單值或者范圍取值,MARK = '*'意味着用戶在Multiple Selection screen 的輸入(即多個條件值);FNAME = '*' 和 MARK = 'ANY',表示所有的屏幕參數都已檢驗完成,即可以對屏幕整體參數做一個整體的檢測了(這里的意思應該就是相當於AT SELECTION-SCREEN)。
? FORM PUT_<node>
最頂層節點<node>所對應的FORM PUT_<node>會在START-OF-SELECTION事件結束后自動被調用,而其他下層節點所對應的FORM會由它的上層節點所對應的FORM中的PUT <node>語句來觸發(在上層節點所對應的可執行程序中的相應GET事件塊執行之后觸發)
PUT <node>.
此語句用是PUT_<node>子過程中的特定語句,它是與PUT_<node> Form一起使用的,通常是放在循環處理數據循環過程中。PUT語句根據LDB的結構指引了報表程序的邏輯。該語句會觸發相應的報表程序的GET <node>事件。當GET事件塊執行完后,如果有下層節點,則還會調用下層節點所對應的FORM PUT_<node>。
PUT語句是該Form(PUT_<node>)中最主要的語句:此語句僅僅只能在LDB數據庫程序的Form中使用。
當PUT_<node>調用結束后,報表程序中相應GET <node> LATE事件塊也會自動調用。
首先,根節點所對應的PUT_<root>會自動執行,此Form中的PUT <node>會以下面的先后順序來執行程序:
1. 如果LDB數據庫程序包含了AUTHORITY_CHECK_<table>語句,則PUT語句的第一件事就是調用它
2. 然后,PUT語句會觸發報表程序相應的GET事件
3. 再后,PUT語句會去調用LDB程序中下一節點的PUT_<node>子過程(此過程又會按照這里的三步來運行),直到下層所有子孫節點PUT_<node>過程處理完成(深度遍歷),才會回到最上一層節點的PUT語句
4. 當控制權從下層節點的PUT_<node>返回時,PUT語句還會觸發當前節點的GET <node> LATE報表事件
GET事件塊會在LDB程序從數據庫表中讀取到一行數據時被觸發。
6.5. LDB選擇屏幕:靜(動)態選擇屏幕、動態選擇視圖
在報表選擇屏幕上是否顯示LDB的普通選擇條件(即靜態的,與動態選擇條件相對應),則要看報表程序中是否使用了對應的 TABLE <node>語句,如果有,則與<node>節點相關的所有LDB選擇條件都會顯示在報表程序的選擇屏幕上,如果沒有此語句,則與<node>節點相關的所有LDB選擇條件都會不會顯示(但如果某個節點沒有在TABLE語句中進行定義,但其子節點,或子孫節點在TABLE語句中進行了定義,則這些子孫節點所對應的父節點所對應LDB屏幕選擇條件還是會嵌入到報表選擇屏幕中)。有幾種情況:
則報表程序的選擇屏幕只會將spfli節點相關的普通選擇條件內嵌進來,子孫節點不會顯示出來:
l 如果報表程序只有子孫節點定義語句:
則報表程序的選擇屏幕中,會將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這一級開始(包括)向上所有節點的所對應的字段,如果納入了選擇視圖中,則選擇屏幕顯示如下: