Довольно типичная задача, но я застрял на том, чтобы делать это красиво.

Например, мне нужно найти последнюю отправку для каждого поставщика, то есть найти доставку с максимальной датой для каждого поставщика

VENDOR     DELIVERY   DATE
10          00055    01/01/2019
20          00070    01/19/2019
20          00088    01/20/2019
20          00120    11/22/2019
40          00150    04/01/2019
40          00200    04/10/2019

Таблица результатов для заполнения

VENDOR     DELIVERY   DATE
10          00055    01/01/2019
20          00120    11/22/2019
40          00200    04/10/2019

Я реализовал это следующим образом, через DESCENDING, что я нахожу очень уродливым

LOOP AT itab ASSIGNING <wa> GROUP BY ( ven_no = <wa>-ven_no ) REFERENCE INTO DATA(vendor).
  LOOP AT GROUP vendor ASSIGNING <ven> GROUP BY ( date = <vendor>-date ) DESCENDING.
    CHECK NOT line_exists( it_vend_max[ ven_no = <ven>-ven_no ] ).
    it_vend_max = VALUE #( BASE it_vend_max ( <ven> ) ).
  ENDLOOP.
ENDLOOP.

Есть ли более элегантный способ сделать это?

Я также пытался REDUCE

result = REDUCE #( vend_line = value ty_s_vend()
                   MEMBERS = VALUE ty_t_vend( )
                   FOR GROUPS <group_key> OF <wa> IN itab
                   GROUP BY ( key = <wa>-ven_no count = GROUP SIZE
                   ASCENDING
         NEXT vend_line = VALUE #(
              ven_no = <wa>-ven_no

              date  = REDUCE i( INIT max = 0
                                FOR m IN GROUP <group_key>
                                NEXT max = nmax( val1 = m-date
                                                 val2 = <wa>-date ) )
              deliv_no  = <wa>-deliv_no
         MEMBERS = VALUE ty_s_vend( FOR m IN GROUP <group_key> ( m ) ) ).

Но REDUCE выбирает максимальную дату из всей таблицы и выбирает только плоскую структуру , а это не то, что мне нужно. Однако в примерах ABAP я видел примеры, где также возможны сокращения от таблицы к таблице. Я ошибся?

Еще я попробовал найти уникальные символы с WITHOUT MEMBERS, но этот синтаксис не работает:

it_vend_max = VALUE ty_t_vend( FOR GROUPS value OF <line> IN itab 
                               GROUP BY ( <line>-ven_no <line>-ship_no ) 
                               WITHOUT MEMBERS ( lifnr = value 
                                                 date = nmax( val1 = <line>-date 
                                                              val2 = value-date ) ) ).

Любое предположение о том, что здесь не так или собственное элегантное решение приветствуется.

0
Suncatcher 11 Апр 2019 в 22:59

2 ответа

Лучший ответ

Если не слишком сложно, я думаю, что лучше использовать одно конструкционное выражение, которое показывает, что целью выражения является инициализация одной переменной и ничего больше.

Лучшее, что я мог сделать, чтобы быть самым эффективным и самым коротким из возможных, но я не могу сделать его элегантным:

TYPES ty_ref_s_vend TYPE REF TO ty_s_vend.

result = VALUE ty_t_vend(
    FOR GROUPS <group_key> OF <wa> IN itab
    GROUP BY ( ven_no = <wa>-ven_no ) ASCENDING
    LET max2 = REDUCE #(
        INIT max TYPE ty_ref_s_vend
        FOR <m> IN GROUP <group_key>
        NEXT max = COND #( WHEN max IS NOT BOUND
                             OR <m>-date > max->*-date
                           THEN REF #( <m> ) ELSE max ) )
    IN ( max2->* ) ).

Как вы можете видеть, я использую ссылку на данные (aux_ref_s_vend2) для повышения производительности, чтобы указать на строку с самой последней датой. Это теоретически быстрее, чем копирование байтов всей строки, но это менее читабельно. Если у вас нет огромной таблицы, не будет большой разницы между использованием вспомогательной ссылки на данные или вспомогательного объекта данных.

PS: я не мог проверить это, потому что вопрос не предоставляет MCVE.

Вот еще одно решение, если вы действительно хотите использовать REDUCE в выражении основного конструктора (но это не нужно):

result = REDUCE ty_t_vend(
    INIT vend_lines TYPE ty_t_vend
    FOR GROUPS <group_key> OF <wa> IN itab
    GROUP BY ( ven_no = <wa>-ven_no ) ASCENDING
    NEXT vend_lines = VALUE #(
        LET max2 = REDUCE ty_ref_s_vend(
            INIT max TYPE ty_ref_s_vend
            FOR <m> IN GROUP <group_key>
            NEXT max = COND #( WHEN max IS NOT BOUND
                                 OR <m>-date > max->*-date
                               THEN REF #( <m> ) ELSE max ) )
        IN BASE vend_lines
        ( max2->* ) ) ).
1
Sandra Rossi 12 Апр 2019 в 16:03

Что вы подразумеваете под элегантным решением? Использование GROUP или REDUCE с «новым» синтаксисом abap не делает его элегантным, по крайней мере, для меня ...

Для меня кодирование, которое легко понять каждому, элегантно:

SORT itab BY vendor date DESCENDING.
DELETE ADJACENT DUPLICATES from itab COMPARING vendor.

Или, если пример более сложный, простое LOOP AT с IF или AT в его APPENDING агрегированных строках для нового itab также решит эту проблему. Пример здесь.

0
futu 14 Апр 2019 в 21:13