使用表解析对Itab进行分组+聚合

时间:2019-04-11 19:59:18

标签: sap grouping aggregate abap

这是比较典型的任务,但我坚持以优美的方式完成任务。

例如,我需要查找每个供应商的最后一批货,即查找每个供应商的最大日期的送货信息

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

任何关于这里出什么问题或自己的优雅解决方案的建议都将受到赞赏。

2 个答案:

答案 0 :(得分:1)

如果不太复杂,我认为最好使用一个构造表达式,这表明该表达式的目标是初始化一个变量,而别无其他。

我能做的最好的事情就是尽可能地表现最好,最短,但是我无法做到优雅:

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 :(得分:0)

优雅的解决方案是什么意思?至少对于我来说,使用GROUP或REDUCE以及“ new” abap语法并不能使其变得优雅。

对我来说,每个人都容易理解的编码很优雅:

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

或者,如果示例更复杂,则简单的LOOP AT中包含IFAT的行APPENDING到新的itab的聚合行也可以解决。 Example here