The article described author’s approach for fast and consistent database update. The approach is speeding up development without decreasing of application robustness.
About SAP LUW
As a rule data of business transactions are updated in several tables (not only in one). It is very important to update all tables or do not update any (it is called to provide data consistency). In SAP NetWeaver to ensure data consistency database updation is not executed directly, but registered for a separate work process and executed in a single DB LUW. Details of that approach are described in abap help. Technically there are several approach for bundling of database updation statements from SAP LUW into separate DB LUW. But the popular and very old one is using CALL FUNCTION … IN UPDATE TASK. Let’s see example of how it works for one table.
Example of using CALL FUNCTION … IN UPDATE TASK
Let we have a table with the following structure
Structure of table ZTC8A005_SAMPLE (the separate entity) | ||
---|---|---|
Field ID | Data Type | Comment |
MANDT | MANDT | Key |
ENTITY_GUID | CHAR32 | Key |
ENTITY_PARAM1 | CHAR10 | Sample of short char-field |
ENTITY_PARAM2 | NUMC10 | Sample of numc-field |
ENTITY_PARAM3 | SYUZEIT | Sample of time-field |
ENTITY_PARAM4 | SYDATUM | Sample of date-field |
ENTITY_PARAM5 | TIMESTAMP | Sample of TIMESTAMP (dec-field) |
ENTITY_PARAM6 | INT4 | Sample of integer-field |
We need to create update function module to provide table consistent updation with UPDATE TASK and pass the content of our internal table by value (let me name the function Z_C8A_005_DEMO_UPD_SAMPLE). That means that separate table type also should be created. So update function module and table type could be like shown below on the screenshots (pictures 1, 2, 3).
As for code itself in update function module it could be simple. Below is code listing for that
FUNCTION z_c8a_005_demo_upd_sample.
*"----------------------------------------------------------------------
*" IMPORTING
*" VALUE(IV_UPDKZ) TYPE UPDKZ DEFAULT 'M'
*" VALUE(IT_SAMPLE) TYPE ZTC8A005_SAMPLE_TAB_TYPE
*"----------------------------------------------------------------------
DATA lc_modify_tab TYPE updkz VALUE 'M'.
DATA lc_upd_tab TYPE updkz VALUE 'U'.
DATA lc_del_tab TYPE updkz VALUE 'D'.
IF it_sample IS INITIAL.
EXIT.
ENDIF.
CASE iv_updkz.
WHEN lc_modify_tab.
MODIFY ztc8a005_sample FROM TABLE it_sample.
WHEN lc_upd_tab.
UPDATE ztc8a005_sample FROM TABLE it_sample.
WHEN lc_del_tab.
DELETE ztc8a005_sample FROM TABLE it_sample.
WHEN OTHERS.
ENDCASE.
ENDFUNCTION.
The sample of using update function could be as on the code listing
DATA lt_sample_tab TYPE STANDARD TABLE OF ztc8a005_sample.
lt_sample_tab = VALUE #(
( entity_guid = 'FUNC_GUID_MOD' entity_param1 = 'CHAR10' entity_param2 = '0504030201' )
( entity_guid = 'FUNC_GUID2_MOD' entity_param1 = '2CHAR10' entity_param2 = '0102030405' )
( entity_guid = 'FUNC_GUID2_DEL' entity_param1 = '2CHAR10' entity_param2 = '777909034' ) ).
CALL FUNCTION 'Z_C8A_005_DEMO_UPD_SAMPLE'
IN UPDATE TASK
EXPORTING
it_sample = lt_sample_tab.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING
wait = abap_true.
In a similar way we could create function modules and table types for any custom table.
What we get:
- the created functions which provide data consistency
- some time spend with keyboard
- additional objects in the transport request
But could we provide data consistency and do not create additional objects? Yes 🙂
Utility AnyTab UpdateTask helps with that. Detailed description and utility itself with demo-reports are available on github-project AnyTab UpdateTask.
Let us see how could be the sample with direct update function transformed
DATA lc_db_tab_sample TYPE tabname VALUE 'ZTC8A005_SAMPLE'.
DATA lt_sample_tab TYPE STANDARD TABLE OF ztc8a005_sample.
lt_sample_tab = VALUE #(
( entity_guid = 'FUNC_GUID_MOD' entity_param1 = 'CHAR10' entity_param2 = '0504030201' )
( entity_guid = 'FUNC_GUID2_MOD' entity_param1 = '2CHAR10' entity_param2 = '0102030405' )
( entity_guid = 'FUNC_GUID2_DEL' entity_param1 = '2CHAR10' entity_param2 = '777909034' ) ).
NEW zcl_c8a005_save2db(
)->save2db( iv_tabname = lc_db_tab_sample
it_tab_content = lt_sample_tab )->do_commit_if_any( ).
The same class and methods could be used in case of many tables. Below is an example for several tables.
DATA lc_db_tab_sample TYPE tabname VALUE 'ZTC8A005_SAMPLE'.
DATA lt_sample_tab TYPE STANDARD TABLE OF ztc8a005_sample.
DATA lt_sample_empty_tab TYPE STANDARD TABLE OF ztc8a005_sample.
DATA lt_head_tab TYPE STANDARD TABLE OF ztc8a005_head.
DATA lt_item_tab TYPE STANDARD TABLE OF ztc8a005_item.
DATA lv_ts TYPE timestamp.
DATA lo_saver_anytab TYPE REF TO zcl_c8a005_save2db.
GET TIME STAMP FIELD lv_ts.
lt_sample_tab = VALUE #(
( entity_guid = 'ANY_GUID_MOD' entity_param1 = 'CHAR10' entity_param2 = '0504030201'
entity_param3 = sy-uzeit entity_param4 = sy-datum entity_param5 = lv_ts )
( entity_guid = 'ANY_GUID2_MOD' entity_param1 = '2CHAR10' entity_param2 = '0102030405'
entity_param3 = sy-uzeit entity_param4 = sy-datum entity_param5 = lv_ts )
( entity_guid = 'ANY_GUID2_DEL' entity_param1 = '2CHAR10' entity_param2 = '777909034'
entity_param3 = sy-uzeit entity_param4 = sy-datum entity_param5 = lv_ts )
).
lt_head_tab = VALUE #(
( head_guid = 'ANY_GUID_UPD' head_param1 = 'ANY_GUID_ADD' head_param2 = '9988776655'
head_param3 = sy-uzeit head_param4 = sy-datum head_param5 = lv_ts )
( head_guid = 'ANY_GUID2_UPD' head_param1 = 'ANY_GUID2_ADD' head_param2 = '9988776655'
head_param3 = sy-uzeit head_param4 = sy-datum head_param5 = lv_ts )
( head_guid = 'ANY_GUID_DEL' head_param1 = 'ANY_GUID_ADD' head_param2 = '9988774444'
head_param3 = sy-uzeit head_param4 = sy-datum head_param5 = lv_ts )
( head_guid = 'ANY_GUID2_DEL' head_param1 = 'ANY_GUID2_ADD' head_param2 = '9988774444'
head_param3 = sy-uzeit head_param4 = sy-datum head_param5 = lv_ts )
).
lt_item_tab = VALUE #(
( head_guid = 'ANY_GUID_UPD' item_guid = 'ANY_ITEM_GUID_ADD' item_param1 = '2CHAR10' item_param2 = '9988776655'
item_param3 = sy-uzeit item_param4 = sy-datum item_param5 = lv_ts )
( head_guid = 'ANY_GUID2_UPD' item_guid = 'ANY_ITEM_GUID2_ADD' item_param1 = '2CHAR10'
item_param3 = sy-uzeit item_param4 = sy-datum item_param5 = lv_ts )
( head_guid = 'ANY_GUID_DEL' item_guid = 'ANY_ITEM_GUID_ADD' item_param2 = '9988776655'
item_param3 = sy-uzeit item_param4 = sy-datum item_param5 = lv_ts )
( head_guid = 'ANY_GUID2_DEL' item_guid = 'ANY_ITEM_GUID2_ADD' item_param1 = '2CHAR10'
item_param3 = sy-uzeit item_param4 = sy-datum item_param5 = lv_ts )
).
CREATE OBJECT lo_saver_anytab.
lo_saver_anytab->save2db( EXPORTING iv_tabname = lc_db_tab_sample
it_tab_content = lt_sample_tab ).
lo_saver_anytab->save2db( EXPORTING iv_tabname = 'ZTC8A005_HEAD'
it_tab_content = lt_head_tab ).
lo_saver_anytab->save2db( EXPORTING iv_tabname = 'ZTC8A005_ITEM'
it_tab_content = lt_item_tab ).
CLEAR lt_sample_empty_tab.
lo_saver_anytab->save2db( EXPORTING iv_tabname = lc_db_tab_sample
it_tab_content = lt_sample_empty_tab ).
" database changes are to be after commit-command (which is in method do_commit_if_any )
" empty table does not take into account while commit command
lo_saver_anytab->do_commit_if_any( ).
Also it is possible not to pass table name
DATA lt_sample_tab TYPE STANDARD TABLE OF ztc8a005_sample.
lt_sample_tab = VALUE #(
( entity_guid = 'ANY_SIMPL_GUID_MOD' entity_param1 = 'CHAR10' entity_param2 = '0504030201' )
( entity_guid = 'ANY_SIMPL_GUID2_MOD' entity_param1 = '2CHAR10' entity_param2 = '0102030405' )
( entity_guid = 'ANY_SIMPL_GUID2_DEL' entity_param1 = '2CHAR10' entity_param2 = '777909034' )
).
CREATE OBJECT lo_saver_anytab.
lo_saver_anytab->save2db( EXPORTING it_tab_content = lt_sample_tab )->do_commit_if_any( ).
Typing of internal table could be by different options.
DATA lt_sample01 TYPE ztc8a005_sample_tab_type. " by table type
" recomended:
DATA lt_sample02 TYPE STANDARD TABLE OF ztc8a005_sample. " dynamical typing by STANDARD TABLE OF DB_tabname
" Could by on the basis of interface
INTERFACE ltc_interface4type.
TYPES ts_data TYPE ztc8a005_sample.
TYPES tt_data TYPE STANDARD TABLE OF ts_data WITH DEFAULT KEY.
ENDINTERFACE.
DATA lt_sample03 TYPE STANDARD TABLE OF ltc_interface4type=>ts_data.
Details of the ABAP-utility is available in github-project AnyTab UpdateTask. I want to pay attention that core of the utility and demo-reports are in different packages. So you can leave DEMO-reports in development system, but core-utility use for the whole system landscape.
I will appreciate any comments, question and stars 🙂
Conclusion
I think it is possible to speed up ABAP-development with utility AnyTab UpdateTask. But what do you think about that? Please share your feedback and thoughts in comment to the blog post.
Also please read and check blogs in ABAP Community and propose your comments and answers to questions 🙂