首页 > 代码库 > [ABAP技术总结]逻辑数据库
[ABAP技术总结]逻辑数据库
原文出自:
6. 逻辑数据库
6.1. 组成
6.2. 结构
6.3. 选择屏幕(Selections)
6.3.1. PARAMETERS屏幕参数扩充
6.3.2. SELECTION-SCREEN格式化屏幕
6.3.3. DYNAMIC SELECTIONS动态选择条件
6.3.3.1. DYN_SEL
6.3.3.1.1. RSDS_TYPE-CLAUSES
6.3.3.1.2. RSDS_TYPE-TRANGE
6.3.4. FIELD SELECTION动态选择字段
6.3.4.1. SELECT_FIELDS
6.4. 数据库程序中重要FORM
6.5. 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屏幕选择条件还是会嵌入到报表选择屏幕中)。有几种情况:
l 如果报表程序中只有根节点的定义语句:
则报表程序的选择屏幕只会将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这一级开始(包括)向上所有节点的所对应的字段,如果纳入了选择视图中,则选择屏幕显示如下:
[ABAP技术总结]逻辑数据库