引用:http://mfg.kingdee.com/pages/chunguangz/blog/archive/2010/03/18/401671.aspx
还可参考:http://www.doc88.com/p-695113351281.html
BW提供了在R3端,自定义数据源的功能,与FILE和WEBSERVICE相比,可以方便ABAP人员开发维护,并且,轻松实现了DELTA 的功能。
自定义的数据源的数据提取方式分为3种:
1)数据库/视图:SAP提供的这种提取方式,系统为你定义好了提取程序,通过在数据库中,设置增量相关字段(如:时间戳、日期、数字),来轻松实现DELTA(增量)抽取,是BW中最常用的自定义数据源,一般是通过程序将数据写入表中。
2) 信息集:即:SAP QUERY。可以设置表间相关的逻辑,相当于JOIN语句,把关联的字段作为数据源。
3) FUNCTION MODULE:通过程序控制数据的提取,可以设置增量字段,也可以不设置,通过一定逻辑将数据抽取,可以实现前两种方式的自定义开发。这是最灵活的自定义数据源。
下面,我们以数据库和FM的方式为例,介绍自定义数据源的应用:
数据库/视图:
1. 创建用于数据源的数据表:(SE11将允许表 维护勾选,方便测试)
其中,UPT_TIMESTAMP是我们设置的增量相关字段:
2. 创建自定义数据源:(RSO2)
创 建ZRSO01数据源,点击“创建”:
按以下参数输入,提取结构不允许输入,激活后,系统会为数据源自动创建,点击“一般增量”按钮:
按 以下屏幕输入参数,并保存:
增量字段名:这个字段在数据库中存放了录入时间戳(或日期或数字),数据抽取程序会按照BW请求的时间参数从数据库中 抽取数据。
时间标记:通过时间戳方式实现增量,即:YYYYMMDDhhmmss格式。
日历天数:按照天为单位实现增量。
数字指 针:按照数字增量抽取。
安全间隔上限:如果“时间标记”或“日历天数”勾选,那么此次可以设置,表示将请求时间戳 减去上限设置的间隔后的时间戳作为数据抽取条件。
举例如下:
BW最后一个抽取时间戳为 20100101120000,下次抽取时间为20100101123000,用户在12:25分做了一个记录,直到12:35才保存。这样,这个记录将不被抽取到BW中。我们设置的间隔上限,就是为了防止这样的情况,如我们设置3600,表示在123000抽取的时候,将1小时之前的记录再次抽取一遍,这样防止数据的遗漏。重复抽取的数据只能将对DELTA抽取有影响,我们只能使用通过DSO上载的方式才能保证上载的数据正确。具体的解释将在DELTA 抽取原理文章中介绍。同理,对于数据指针,我们不是设置上限,而是设置下限,请根据您的需求具体设置。
实时的激活:SAP解释是是否适用于RDA 方式的数据源。
更改记录的新状态/附加增量:更改记录的新状态即表示使用后镜像(AIE)的方式上载数据。附加增量表示以ADD方式上载数据。也是DELTA原理的内容,以后在介绍,我们这里选择AIE的方式上载。(简单说就是以最后更改的记录为准上载。ADD即将改变的差额上载)
3. 执行数据源:
接下来,我们要在BW数据源中复制目录下的元数据,并激活数据源,然后创建信息包,此处不再赘述。其中,初始化信息包公司代码被限制为 1003。
向数据库中手工添加数据(SE16):
执行初始化信息包:
我们会在RSA7中,查看多了ZDSO01的初始 化记录和统计信息
点击 ,查看统计记录:
从中,我们可以看出BW系统请求的时间戳为20100318002659。
查 看数据源的请求记录,生成以下记录:
表示数据源中,1003的4条记录被抽取到BW中:
接下来,我们在数据库中在录入2条记 录,如下:
然后执行增量抽取信息包,结果如下,只将一条记录上载
我用的版本比较低,在这里,安全间隔没有起作用。
在上 载前可以使用RSA3测试,可以在FM RSA3_GEN_GET_DATA上设置断点,查看SELECT语句:
* Open Cursor for dynamical SELECT
open cursor with hold g_cursor for
select * from (g_s_oltpsource-extractor)
where (l_t_dynamic_select).
endif.
* Fetch first data package
fetch next cursor g_cursor
appending corresponding fields of table e_t_data
package size g_s_interface-maxsize.
使用Function Module抽取数据:
基本与以上步骤相同,我们以提取上例中的表数据为例,在数据源设置FM:
下面介绍FM的创建:
到 SE80中复制FUNCTION GROUP RSAX,到新的FG:
选择RSAX_BIW_GET_DATA_SIMPLE,选择 复制,
复制到我们自己的FM Z_GET_DATA_FM
对FM进行修改,要点如下:
1)将TABLES中的 E_T_DATA的参考值,改为我们的数据源表。
2)修改源程序:程序中,注明MY COMMENT的地方是需要我们修改的位置。大家可以通过RSA3测试跟踪下效果,此处不再赘述,其他与数据库数据源是一样的。
FUNCTION Z_GET_DATA_FM.
*"----------------------------------------------------------------------
*"*"Local interface:
*" IMPORTING
*" VALUE(I_REQUNR) TYPE SRSC_S_IF_SIMPLE-REQUNR
*" VALUE(I_DSOURCE) TYPE SRSC_S_IF_SIMPLE-DSOURCE OPTIONAL
*" VALUE(I_MAXSIZE) TYPE SRSC_S_IF_SIMPLE-MAXSIZE OPTIONAL
*" VALUE(I_INITFLAG) TYPE SRSC_S_IF_SIMPLE-INITFLAG OPTIONAL
*" VALUE(I_READ_ONLY) TYPE SRSC_S_IF_SIMPLE-READONLY OPTIONAL
*" VALUE(I_REMOTE_CALL) TYPE SBIWA_FLAG DEFAULT SBIWA_C_FLAG_OFF
*" TABLES
*" I_T_SELECT TYPE SRSC_S_IF_SIMPLE-T_SELECT OPTIONAL
*" I_T_FIELDS TYPE SRSC_S_IF_SIMPLE-T_FIELDS OPTIONAL
*" E_T_DATA STRUCTURE ZZC_TEST02 OPTIONAL
*" EXCEPTIONS
*" NO_MORE_DATA
*" ERROR_PASSED_TO_MESS_HANDLER
*"----------------------------------------------------------------------
* Example: DataSource for table SFLIGHT
* tables: sflight. "MY COMMNET
TABLES: ZZC_TEST02.
* Auxiliary Selection criteria structure
DATA: L_S_SELECT TYPE SRSC_S_SELECT.
* Maximum number of lines for DB table
STATICS: S_S_IF TYPE SRSC_S_IF_SIMPLE,
* counter
S_COUNTER_DATAPAKID LIKE SY-TABIX,
* cursor
S_CURSOR TYPE CURSOR.
* Select ranges
* RANGES: L_R_CARRID FOR SFLIGHT-CARRID, "MY COMMENT
* L_R_CONNID FOR SFLIGHT-CONNID. "MY COMMENT
RANGES: L_R_BUKRS FOR T001-BUKRS.
RANGES: L_R_TIMES FOR ZZC_TEST02-UPT_TIMESTAMP.
* Initialization mode (first call by SAPI) or data transfer mode
* (following calls) ?
IF I_INITFLAG = SBIWA_C_FLAG_ON.
************************************************************************
* Initialization: check input parameters
* buffer input parameters
* prepare data selection
************************************************************************
* Check DataSource validity
CASE I_DSOURCE.
* when '0SAPI_SFLIGHT_SIMPLE'. "MY COMMENT
WHEN 'ZRSO02'.
WHEN OTHERS.
IF 1 = 2. MESSAGE E009(R3). ENDIF.
* this is a typical log call. Please write every error message like this
LOG_WRITE 'E' "message type
'R3' "message class
'009' "message number
I_DSOURCE "message variable 1
' '. "message variable 2
RAISE ERROR_PASSED_TO_MESS_HANDLER.
ENDCASE.
APPEND LINES OF I_T_SELECT TO S_S_IF-T_SELECT.
* Fill parameter buffer for data extraction calls
S_S_IF-REQUNR = I_REQUNR.
S_S_IF-DSOURCE = I_DSOURCE.
S_S_IF-MAXSIZE = I_MAXSIZE.
* Fill field list table for an optimized select statement
* (in case that there is no 1:1 relation between InfoSource fields
* and database table fields this may be far from beeing trivial)
APPEND LINES OF I_T_FIELDS TO S_S_IF-T_FIELDS.
ELSE. "Initialization mode or data extraction ?
************************************************************************
* Data transfer: First Call OPEN CURSOR + FETCH
* Following Calls FETCH only
************************************************************************
* First data package -> OPEN CURSOR
IF S_COUNTER_DATAPAKID = 0.
* Fill range tables BW will only pass down simple selection criteria
* of the type SIGN = 'I' and OPTION = 'EQ' or OPTION = 'BT'.
* MY COMMENT
* loop at s_s_if-t_select into l_s_select where fieldnm = 'CARRID'.
* move-corresponding l_s_select to l_r_carrid.
* append l_r_carrid.
* endloop.
*
* loop at s_s_if-t_select into l_s_select where fieldnm = 'CONNID'.
* move-corresponding l_s_select to l_r_connid.
* append l_r_connid.
* endloop.
*
LOOP AT S_S_IF-T_SELECT INTO L_S_SELECT WHERE FIELDNM = 'BUKRS'.
MOVE-CORRESPONDING L_S_SELECT TO L_R_BUKRS.
APPEND L_R_BUKRS.
ENDLOOP.
LOOP AT S_S_IF-T_SELECT INTO L_S_SELECT WHERE FIELDNM =
'UPT_TIMESTAMP'.
MOVE-CORRESPONDING L_S_SELECT TO L_R_TIMES.
APPEND L_R_TIMES.
ENDLOOP.
* Determine number of database records to be read per FETCH statement
* from input parameter I_MAXSIZE. If there is a one to one relation
* between DataSource table lines and database entries, this is trivial.
* In other cases, it may be impossible and some estimated value has to
* be determined.
OPEN CURSOR WITH HOLD S_CURSOR FOR
* SELECT (S_S_IF-T_FIELDS) FROM SFLIGHT "MY COMMENT
* WHERE CARRID IN L_R_CARRID AND
* CONNID IN L_R_CONNID.
SELECT * FROM ZZC_TEST02
WHERE BUKRS IN L_R_BUKRS
AND UPT_TIMESTAMP IN L_R_TIMES.
ENDIF. "First data package ?
* Fetch records into interface table.
* named E_T_'Name of extract structure'.
FETCH NEXT CURSOR S_CURSOR
APPENDING CORRESPONDING FIELDS
OF TABLE E_T_DATA
PACKAGE SIZE S_S_IF-MAXSIZE.
IF SY-SUBRC <> 0.
CLOSE CURSOR S_CURSOR.
RAISE NO_MORE_DATA.
ENDIF.
S_COUNTER_DATAPAKID = S_COUNTER_DATAPAKID + 1.
ENDIF. "Initialization mode or data extraction ?
ENDFUNCTION.
下面是在scn里找到的解释,我总结了一下要点
对RSAX_BIW_GET_DATA_SIMPLE这个FM进行修改,要点如下:
1)将TABLES中的E_T_DATA的参考值,改为我们的数据源表。
2)要被调用2次,一次初始化操作,一次数据抽取,使用 输入参数I_INITFLAG作为判断标识
3)如果确认是最后的数据包,需要RAISE NO_MORE_DATA,否则会一直抽取
英文原文
How does the extraction api work in case you are extracting data using a self defined function module with generic delta?
Sometimes, if your application or requirement makes it necessary, you have to create your own function module to extract the data from whatever sap system to bw.
Therefore you normally make a copy of the standard fm 'RSAX_BIW_GET_DATA_SIMPLE'. To make this new function work for you, you have to realize the following.
1.) the fm gets called by the extraction api for at least 2 times. First time is for initialization and from the 2nd time on it is for data extraction.
2.) right after the last data package (somehow you need to make sure that it is the last one) you have to raise the exception no_more_data.
Example with lots of comments
FUNCTION RSAX_BIW_GET_DATA_SIMPLE.
*"--------------------------------------------------------------------------
*"*"Lokale Schnittstelle:
*" IMPORTING
*" VALUE(I_REQUNR) TYPE SRSC_S_IF_SIMPLE-REQUNR
*" VALUE(I_DSOURCE) TYPE SRSC_S_IF_SIMPLE-DSOURCE OPTIONAL
*" VALUE(I_MAXSIZE) TYPE SRSC_S_IF_SIMPLE-MAXSIZE OPTIONAL
*" VALUE(I_INITFLAG) TYPE SRSC_S_IF_SIMPLE-INITFLAG OPTIONAL
*" VALUE(I_READ_ONLY) TYPE SRSC_S_IF_SIMPLE-READONLY OPTIONAL
*" TABLES
*" I_T_SELECT TYPE SRSC_S_IF_SIMPLE-T_SELECT OPTIONAL
*" I_T_FIELDS TYPE SRSC_S_IF_SIMPLE-T_FIELDS OPTIONAL
*" E_T_DATA STRUCTURE SFLIGHT OPTIONAL
*" EXCEPTIONS
*" NO_MORE_DATA
*" ERROR_PASSED_TO_MESS_HANDLER
*"--------------------------------------------------------------------------
* Auxiliary Selection criteria structure
DATA: L_S_SELECT TYPE SRSC_S_SELECT.
* Maximum number of lines for DB table
STATICS: S_S_IF TYPE SRSC_S_IF_SIMPLE,
* counter
S_COUNTER_DATAPAKID LIKE SY-TABIX,
* cursor
S_CURSOR TYPE CURSOR.
* Initialization mode (first call by SAPI) or data transfer mode
IF I_INITFLAG = SBIWA_C_FLAG_ON.
* the coding here will be processed the first time the fm gets called.
* it is used to populate static or global variables and to check wether
* it's called by the right datasource or not.
ELSE. "Initialization mode or data extraction ?
* this part will be executed from the 2nd call on
* First data package -> OPEN CURSOR
IF S_COUNTER_DATAPAKID = 0.
* in case it is for the first data package, range tabs gets filled, a cursor will
* be opened or a initial dataset will be read from database into a global internal table
* this has to be done here, with the first data package, to avoid getting the same data with
* each call of the fm.
* additionally you can check wether you get select-options for your 'generic delta'-field or not,
* and, if it is provided, you are able to set a flag in order to do different selections
* based on this flag for delta or full load.
ENDIF. "First data package ?
* from now on records gets fetched from the database or gets read from the internal table
* and the return table e_t_data gets populated with the number of rows given by parameter s_s_if-maxsize.
* if the last record is populated to table e_t_data you need to raise the exeption no_more_data
* and you need to close the cursor, if you opened one.
* with each data package you also have to increase s_counter_datapakid.
ENDIF. "Initialization mode or data extraction ?
ENDFUNCTION.
If you forget to raise no_more_data, the extraction api will call the fm forever.