ZDOC_2826

Грязные трюки при работе с ALV

Дано: есть вывод отчета в ALV, в котором стандартными средствами включен расчет среднего значения.

Итоговое среднее значение стандартно расчитывается так:

( 30 + 40 + 50 + 0 ) / 4 = 30

Предположим для примера, что в четвёртой строке нулевое значение связано не с нулевым значением, а с его отсутствием.

Соответственно от заказчика есть задание: требуется выводить среднее значение, не учитывающее пустые (нулевые) значения:

Один из способов решения задачи – грязно вторгнуться во внутреннюю кухню ALV. Приступим?

Если создадим дочерний класс от главного CL_GUI_ALV_GRID, то получим возможность переопределить метод SET_DATA_TABLE.

Вот пример реализации:

METHOD set_data_table.

  CALL METHOD super->set_data_table
    EXPORTING
      no_of_lines = no_of_lines
      first_line  = first_line
    CHANGING
      data_table  = data_table
    EXCEPTIONS
      error       = 1
      OTHERS      = 2.
  IF sy-subrc <> 0.
    RAISE error.
  ENDIF.

  me->get_frontend_fieldcatalog(
    IMPORTING
      et_fieldcatalog = DATA(lt_fc)
  ).

  LOOP AT lt_fc INTO DATA(ls_fc).
    IF ls_fc-do_sum = 'C' AND ls_fc-no_zero = 'X'.
      DATA(lv_mean) = abap_true.

      FIELD-SYMBOLS: <tab> TYPE STANDARD TABLE.
      ASSIGN mt_outtab->* TO <tab>.

      "[TODO] - datatype is INT as proof-of-concept
      DATA(lv_amount) = 0.
      DATA(lv_count) = 0.
      LOOP AT <tab> ASSIGNING FIELD-SYMBOL(<rec>).
        ASSIGN COMPONENT ls_fc-fieldname
          OF STRUCTURE <rec>
          TO FIELD-SYMBOL(<val>).
        IF <val> IS NOT INITIAL.
          lv_count = lv_count + 1.
          lv_amount = lv_amount + <val>.
        ENDIF.
      ENDLOOP.

      DATA(lv_total) = lv_amount / lv_count.

      LOOP AT data_table ASSIGNING FIELD-SYMBOL(<data_total_h>).
        IF <data_total_h>-style = 1048576 AND
           <data_total_h>-value(1) = 'T'.

          READ TABLE data_table ASSIGNING FIELD-SYMBOL(<data_total_v>)
            WITH KEY col_pos = ls_fc-col_pos
                     row_pos = <data_total_h>-row_pos.

          <data_total_v>-value = lv_total.

        ENDIF.
      ENDLOOP.
    ENDIF.
  ENDLOOP.

  "[TODO] - subtotals are not processed, just proof-of-concept
  me->get_subtotals(
    IMPORTING
      et_grouplevels = DATA(lt_levels)
  ).

  IF lv_mean = abap_true.
    super->set_data_table(
      CHANGING
        data_table = mt_data[] ).
    me->set_auto_redraw(
      EXPORTING
        enable = 1 ).
  ENDIF.

ENDMETHOD.

Остаётся только реализовать отчет на базе нашего нового класса.

Поэтому, если изначально отчет был на CL_SALV_TABLE или REUSE_ALV_GRID_DISPLAY, то придётся потратить время и на это тоже. А можно ли хакнуть похожими методами их – отдельная история.

PS. Данный способ можно применять не только для вышеописанной задачи, но и для некоторых других. Например: можно влиять на объединение ячеек по горизонтали или вертикали (merge), если менять значения в полях MERGEHORIZ и MERGEVERT.