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).

Picture 1. Attributes of update function module for table ZTC8A005_SAMPLE

 

Picture 2. Import parameters pass by value for update function

 

Picture 3. Separate table type for table ZTC8A005_SAMPLE

 

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:

  1. the created functions which provide data consistency
  2. some time spend with keyboard
  3. 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( ).

 

Update

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 🙂

Sara Sampaio

Sara Sampaio

Author Since: March 10, 2022

0 0 votes
Article Rating
Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x