ABAP New Features - Internal Tables

Using Secondary keys to Access the Same Internal Table in Different Ways

如下面代码中,我们需要根据number或name读取数据,number定义成hash表的key,因此如果有值将采用number 作为primary key读取,如果number为空将采用name作为second key读取。

    DATA:
    table_of_monsters TYPE HASHED TABLE OF ztsm_monsters WITH UNIQUE KEY monster_number
    WITH NON-UNIQUE SORTED KEY sort COMPONENTS name .

    IF id_monster_number IS NOT INITIAL.
      READ TABLE table_of_monsters INTO es_monsters
      WITH TABLE KEY monster_number = id_monster_number.
    ELSE.
      READ TABLE table_of_monsters INTO es_monsters
      WITH KEY sort COMPONENTS name = id_name ##primkey[sort].
    ENDIF.

如下代码将monster_number bed_number定义为hash key并将monster_number 定义为second key,如果只有monster_number,首先通过read table TRANSPORTING NO FIELDS 检查是否存在,由于定义了second key,内表将可以根据second key做LOOP及read binary search。monster_beds可以作为hash table也可以作为sorted table。

    DATA:
      monster_beds TYPE HASHED TABLE OF ztvc_monstr_beds
                        WITH UNIQUE KEY monster_number bed_number
                        WITH NON-UNIQUE SORTED KEY sort COMPONENTS monster_number,
      start_point  TYPE sy-tabix.

    IF id_bed_number IS NOT INITIAL.
      READ TABLE monster_beds INTO es_beds
      WITH TABLE KEY monster_number = id_monster_number
                     bed_number     = id_bed_number.
    ELSE.
      "No bed, return all bed data for monster
      READ TABLE monster_beds TRANSPORTING NO FIELDS
      WITH KEY sort COMPONENTS monster_number = id_monster_number ##primkey[sort].
      CHECK sy-subrc = 0.
      start_point = sy-tabix.
      LOOP AT monster_beds INTO DATA(monster_bed_record)
      USING KEY sort FROM start_point.
        IF monster_bed_record-monster_number GT id_monster_number.
          EXIT."From Inner Loop
        ENDIF.
        CHECK monster_bed_record-monster_number = id_monster_number.
        APPEND monster_bed_record TO et_monster_beds.
      ENDLOOP.
      SORT et_monster_beds BY monster_number bed_number.
    ENDIF.

Table Work Areas

以前我们一般先定义internal table与work area,7.4以后,我们可以在对内表的操作过程中定义work area及field symbol。

    DATA: monster_number    TYPE zde_monster_number VALUE '000000001',
          table_of_monsters TYPE STANDARD TABLE OF ztsm_monsters.

    READ TABLE table_of_monsters WITH KEY monster_number = monster_number
    INTO DATA(monster_details).

    LOOP AT table_of_monsters INTO DATA(monster_details2).
    ENDLOOP.

    READ TABLE table_of_monsters WITH KEY monster_number = monster_number
    ASSIGNING FIELD-SYMBOL().

    LOOP AT table_of_monsters ASSIGNING FIELD-SYMBOL().
    ENDLOOP.

Reading from a Table

7.4以前Read Table的形式如下

    READ TABLE table_of_monsters INTO monster_details
    WITH KEY name = monster_name.
    monster = zcl_monster=>factory( monster_details-monster_number ).

7.4以后可以内表后面跟[]来替代关键字read table与with key

monster = zcl_monster=>factory( table_of_monsters[ monster_name ]-monster_number ).

我们可以结合string如下使用代码,但这里有个问题,如果访问内表没取到值,将会有异常出现。

    zcl_bc_screen_message=>output(
     |{ monster_name } s Monster Number is {  table_of_monsters[ monster_name ]-monster_number }| ).

可以用如下代码来改善,添加OPTIONAL或DEFAULT来避免异常产生。此时如果为空将返回空值。

    zcl_bc_screen_message=>output(
     |{ monster_name } s Monster Number is { VALUE #( table_of_monsters[ monster_name ]-monster_number OPTIONAL ) }| ).

    zcl_bc_screen_message=>output(
     |{ monster_name } s Monster Number is { VALUE #( table_of_monsters[ monster_name ]-monster_number DEFAULT '9999999999' ) }| ).

CORRESPONDING for Normal Internal Tables

通常我们用MOVE-CORRESPONDING来将结构赋值到另一个结构,当对内表赋值时,代码如下

    DATA: green_monsters TYPE STANDARD TABLE OF ztsm_monsters,
          blue_monsters  TYPE STANDARD TABLE OF ztsm_monsters.

    FIELD-SYMBOLS:
       LIKE LINE OF green_monsters,
        LIKE LINE OF blue_monsters.

    LOOP AT green_monsters ASSIGNING .
      APPEND INITIAL LINE TO blue_monsters
      ASSIGNING .
      MOVE-CORRESPONDING  TO .
      CLEAR -evilness.
      -people_scared =
      -most_peasants_scared.
    ENDLOOP.

7.4后可以用CORRESPONDING来对内表赋值,后面跟的#表示创建的目标表与原始表列相同,Except及Mapping修改了相关的字段。

    green_monsters = CORRESPONDING #(
    blue_monsters
    MAPPING people_scared = most_peasants_scared
    EXCEPT evilness ).

MOVE-CORRESPONDING for Internal Tables with Deep Structures

如下定义内表,european_result 与 us_result都是一个字段加一个内表结构字段,当进行赋值时,虽然内字段的结构不一样,但因为都叫t_result,因此us中lockbox将被赋值上iban的值。

    TYPES: BEGIN OF l_typ_european_monsters,
             monster_name      TYPE string,
             monster_iban_code TYPE string,
           END OF l_typ_european_monsters.

    TYPES: l_tt_european_monsters TYPE HASHED TABLE OF l_typ_european_monsters
                                  WITH UNIQUE KEY monster_name.

    DATA: iban_code_record TYPE l_typ_european_monsters.

    TYPES: BEGIN OF l_typ_european_results,
             laboratory TYPE string,
             t_result   TYPE l_tt_european_monsters,
           END OF l_typ_european_results.

    TYPES: l_tt_european_results TYPE STANDARD TABLE OF l_typ_european_monsters.

    DATA: european_result  TYPE l_typ_european_results,
          european_results TYPE l_tt_european_results.

    TYPES: BEGIN OF l_typ_us_monsters,
             monster_name         TYPE string,
             monster_lockbox_code TYPE string,
           END OF l_typ_us_monsters.

    TYPES: l_tt_us_monsters TYPE HASHED TABLE OF l_typ_us_monsters
                            WITH UNIQUE KEY monster_name.

    TYPES: BEGIN OF l_typ_us_results,
             laboratory TYPE string,
             t_result   TYPE l_tt_us_monsters,
           END OF l_typ_us_results.

    TYPES: l_tt_us_results TYPE STANDARD TABLE OF l_typ_us_results.

    DATA: us_result  TYPE l_typ_us_results,
          us_results TYPE l_tt_us_results.

*--------------------------------------------------------------------*
* Listing 2.60 Attempt at MOVE-CORRESPONDING
*--------------------------------------------------------------------*
    european_result-laboratory         = 'SECRET LABORATORY 51'.
    iban_code_record-monster_name      = 'FRED'.
    iban_code_record-monster_iban_code = 'AL47212110090000000235698741'.
    INSERT iban_code_record INTO TABLE european_result-t_result.
    MOVE-CORRESPONDING european_result TO us_result.

当两个内表结构的字段不一致时,以前我们赋值要用Loop,MOVE-CORRESPONDING结构

    LOOP AT european_results ASSIGNING FIELD-SYMBOL().
      APPEND INITIAL LINE TO us_results ASSIGNING FIELD-SYMBOL().
      MOVE-CORRESPONDING  TO .
    ENDLOOP.

7.4后可以直接MOVE-CORRESPONDING内部操作MOVE-CORRESPONDING european_results TO us_results.,但这个还是没解决上面t_result内表结构字段不同赋值问题。因此7.4引入了MOVE -CORRESPONDING EXPANDING NESTED TABLES,该语句赋值时,首先删除目标表的记录,然后赋值时会校验t_result内表结构字段,如果该字段不同则该字段将不赋值。MOVE-CORRESPONDING KEEPING TARGET LINES可以保留原内表的记录,类似于APPEND LIN ES OF table1 TO table2MOVE -CORRESPONDING EXPANDING NESTED TABLES KEEPING TARGET LINES可以将两者结合起来。

Dynamic MOVE-CORRESPONDING

7.4后不推荐用MOVE-CORRESPONDING,尤其是HANA数据库,可以用如下方法动态匹配。LEVEL参数用在匹配deep structure,kind参数可以填EXCEPT等选项,dstname为目标表的字段,srcname为相应的值,通过cl_abap_corresponding的create及execute方法执行。

    DATA: mapping_record TYPE cl_abap_corresponding=>mapping_info,
          mapping_table  TYPE cl_abap_corresponding=>mapping_table.

    mapping_record-level = 0.
    mapping_record-kind  = cl_abap_corresponding=>mapping_component.

    mapping_record-dstname = 'BEST_BRAIN_01'.

    IF is_monster_header-hat_size > 5.
      mapping_record-srcname = 'BIGGEST_BRAIN'.
    ELSE.
      mapping_record-srcname = 'SMALLEST_BRAIN'.
    ENDIF.

    APPEND mapping_record TO mapping_table.

    mapping_record-dstname = 'BEST_BRAIN_02'.

    IF id_monster_usage = 'MORTGAGE_SALESMAN'.
      mapping_record-srcname = 'EVILEST_BRAIN'.
    ELSEIF id_monster_usage = 'MORRIS_DANCER'.
      mapping_record-srcname = 'WEIRDEST_BRAIN'.
    ENDIF.

    APPEND mapping_record TO mapping_table.

    TRY.
        DATA(dynamic_mapper) =
        cl_abap_corresponding=>create(
            source            = is_possible_brains
            destination       = rs_best_brains
            mapping           = mapping_table ).

        dynamic_mapper->execute(
          EXPORTING source      = is_possible_brains
          CHANGING  destination = rs_best_brains    ).

      CATCH cx_corr_dyn_error.
        "Fatal Error
    ENDTRY.

New Functions for Common Internal Table Tasks

以前我们获取行数通过sy-tabix。

    READ TABLE table_of_monsters WITH KEY monster_number = monster_number
    TRANSPORTING NO FIELDS.

    IF sy-subrc = 0.
      start_row = sy-tabix.
    ENDIF.

现在可以用line_index来获取

 DATA(start_row2) = line_index( table_of_monsters[ monster_number = monster_number ] ).

直接作为放回值使用

    LOOP AT table_of_monsters FROM line_index( table_of_monsters[ monster_number = monster_number ] )
                              ASSIGNING FIELD-SYMBOL().
    ENDLOOP.

判断是否存在也可以用line_exists来替代。

*--------------------------------------------------------------------*
* Listing 2.67 Seeing Whether an Internal Table Line Exists before 7.4
*--------------------------------------------------------------------*
    READ TABLE table_of_monsters ASSIGNING 
    WITH KEY monster_number = monster_number.

    IF sy-subrc NE 0.
      APPEND INITIAL LINE TO table_of_monsters ASSIGNING .
    ENDIF.
    ADD 1 TO -sanity.

*--------------------------------------------------------------------*
* Listing 2.68 Seeing Whether an Internal Table Line Exists in 7.40
*--------------------------------------------------------------------*
    IF line_exists( table_of_monsters[ monster_number = monster_number ] ).
      READ TABLE table_of_monsters ASSIGNING 
      WITH KEY monster_number = monster_number.
    ELSE.
      APPEND INITIAL LINE TO table_of_monsters ASSIGNING .
    ENDIF.

Internal Table Queries with REDUCE

REDUCE可以处理内表并放回一个结果,如下代码,reduce后面跟返回结果的类型,init定义了一个临时变量,FOR循环结束后,result将会被赋值给mad_monsters_count。

    DATA: neurotic_monsters TYPE STANDARD TABLE OF ztsm_monsters.

    DATA(monster) = NEW zcl_monster( ).

    DATA(mad_monsters_count) = REDUCE sy-tabix(
    INIT result = 0
    FOR  monster_details IN neurotic_monsters
    NEXT result = result +
    monster->is_it_mad( monster_details-monster_number ) ).

Grouping Internal Tables

7.4在Loop中引进了Group BY选项,如下代码,根据Main table中的记录,取出每个type下people scared总人数,并做附加条件判断。在外层loop中,Group有两条记录,vamp/x 与 zomb/x,通过debug可以看到外层loop只循环两次,monster->is_it_mad被调用了5次,在循环内,可以通过LOOP AT GROUP ASSIGNING FIELD-SYMBOL()来取出该group组合下Main table中的原始数据,然后进行相应的操作。

    TYPES: tt_monsters TYPE STANDARD TABLE OF ztsm_monsters
                       WITH DEFAULT KEY.

    DATA: monster_sub_set TYPE tt_monsters,
          total_scared    TYPE i.

    DATA(monster) = NEW zcl_monster( ).

    DATA(table_of_monsters) = VALUE tt_monsters(
    ( monster_number = '1' monster_type = 'VAMP' people_scared = 3 )
    ( monster_number = '2' monster_type = 'VAMP' people_scared = 4 )
    ( monster_number = '3' monster_type = 'VAMP' people_scared = 2 )
    ( monster_number = '4' monster_type = 'ZOMB' people_scared = 1 )
    ( monster_number = '5' monster_type = 'ZOMB' people_scared = 1 )
     ).

    LOOP AT table_of_monsters INTO DATA(monster_details)
    GROUP BY ( monster_type   = monster_details-monster_type
               is_it_crackers = monster->is_it_mad( monster_details-monster_number ) )
    ASSIGNING FIELD-SYMBOL().

      CHECK -is_it_crackers = abap_true.

      CLEAR monster_sub_set.

      LOOP AT GROUP  ASSIGNING FIELD-SYMBOL().
        monster_sub_set = VALUE #( BASE monster_sub_set (  ) ).
      ENDLOOP.

      CLEAR total_scared.

      LOOP AT monster_sub_set INTO DATA(sub_set_record).
        ADD sub_set_record-people_scared TO total_scared.
      ENDLOOP.

      WRITE:/ 'Bonkers Monsters of Type',-monster_type,' scared ',total_scared,' people'.

    ENDLOOP.

Extracting One Table from Another

7.4以前我们过滤一个内表的数据到另一个时,只能通过Loop来做,7.4后引入了FILTER。但注意FILTER的内表必须有一个hash key或sorted key。

*--------------------------------------------------------------------*
* Listing 2.72 Extracting One Table from Another before 7.4
*--------------------------------------------------------------------*
    DATA: all_monsters             TYPE SORTED TABLE OF ztsm_monsters
                                   WITH NON-UNIQUE KEY monster_number
                                   WITH NON-UNIQUE SORTED KEY bonkers_ness
                                   COMPONENTS sanity,
          averagely_mad_monsters   TYPE STANDARD TABLE OF ztsm_monsters,
          an_averagely_mad_monster LIKE LINE OF averagely_mad_monsters.

    LOOP AT all_monsters INTO DATA(monster_record)
      WHERE sanity < 75.
      CLEAR an_averagely_mad_monster.
      MOVE-CORRESPONDING monster_record TO an_averagely_mad_monster.
      APPEND an_averagely_mad_monster   TO averagely_mad_monsters.
    ENDLOOP."All Monsters

*--------------------------------------------------------------------*
* Listing 2.73 Extracting One Table from Another in 7.40
*--------------------------------------------------------------------*
    DATA(averagely_mad_monsters2) =
    FILTER #( all_monsters USING KEY bonkers_ness
    WHERE sanity < 75 ).

以前我们取一些复杂组合时,经常在SELECT中用FOR ALL ENTRIES IN,现在,如果程序中前面已经读取了整的pets_of_our_monsters,然后要进行all_monsters的过滤,可以采用下面的方法。同样注意all_monsters有一个hash key或sorted key

*--------------------------------------------------------------------*
* Listing 2.74 FOR ALL ENTRIES during a Database Read
*--------------------------------------------------------------------*
    DATA: monster_pets TYPE SORTED TABLE OF ztmonster_pets
          WITH NON-UNIQUE KEY owner pet_number.

    SELECT *
      FROM ztmonster_pets
      INTO CORRESPONDING FIELDS OF TABLE monster_pets
      FOR ALL ENTRIES IN all_monsters
      WHERE owner = all_monsters-monster_number.

*--------------------------------------------------------------------*
* Listing 2.68 FOR ALL ENTRIES on an Internal Table
*--------------------------------------------------------------------*
    DATA(pets_of_our_monsters) =
    FILTER #( monster_pets IN all_monsters
    WHERE owner = monster_number ).

你可能感兴趣的:(ABAP New Features - Internal Tables)