itab 的分组 + 聚合 table 理解
Grouping + aggregation of itab with table comprehensions
相当典型的任务,但我坚持以漂亮的方式完成它。
例如,我需要找到每个供应商的最后一批货,即找到每个供应商的最大交货日期
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
要填充的结果table
VENDOR DELIVERY DATE
10 00055 01/01/2019
20 00120 11/22/2019
40 00200 04/10/2019
我通过降序实现了这个,我觉得很丑
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
从整个 table 中选择最大日期,它只选择 扁平结构 ,这不是我想要的。但是,在 ABAP 示例中,我看到了 table-to-table 缩减也是可能的样本。我错了吗?
我尝试的另一件事是使用 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 ) ) ).
感谢任何关于此处错误的建议或自己的优雅解决方案。
如果不是太复杂,我认为最好使用一个构造表达式,这表明该表达式的目标是初始化一个变量而不是其他。
我能做的最好是性能最好和最短,但我不能让它优雅:
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
) 来指向具有最新日期的行。理论上它比复制整行的字节要快,但可读性较差。如果你没有巨大的table,使用辅助数据引用或辅助数据对象之间不会有太大区别。
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->* ) ) ).
优雅的解决方案是什么意思?将 GROUP 或 REDUCE 与 "new" abap 语法一起使用并不能使其变得优雅,至少对我而言...
对我来说,大家容易理解的代码才是优雅的:
SORT itab BY vendor date DESCENDING.
DELETE ADJACENT DUPLICATES from itab COMPARING vendor.
或者如果示例更复杂,一个简单的 LOOP AT
和 IF
或 AT
在其中 APPENDING
聚合行到一个新的 itab,也将解决它. .
相当典型的任务,但我坚持以漂亮的方式完成它。
例如,我需要找到每个供应商的最后一批货,即找到每个供应商的最大交货日期
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
要填充的结果table
VENDOR DELIVERY DATE
10 00055 01/01/2019
20 00120 11/22/2019
40 00200 04/10/2019
我通过降序实现了这个,我觉得很丑
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
从整个 table 中选择最大日期,它只选择 扁平结构 ,这不是我想要的。但是,在 ABAP 示例中,我看到了 table-to-table 缩减也是可能的样本。我错了吗?
我尝试的另一件事是使用 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 ) ) ).
感谢任何关于此处错误的建议或自己的优雅解决方案。
如果不是太复杂,我认为最好使用一个构造表达式,这表明该表达式的目标是初始化一个变量而不是其他。
我能做的最好是性能最好和最短,但我不能让它优雅:
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
) 来指向具有最新日期的行。理论上它比复制整行的字节要快,但可读性较差。如果你没有巨大的table,使用辅助数据引用或辅助数据对象之间不会有太大区别。
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->* ) ) ).
优雅的解决方案是什么意思?将 GROUP 或 REDUCE 与 "new" abap 语法一起使用并不能使其变得优雅,至少对我而言...
对我来说,大家容易理解的代码才是优雅的:
SORT itab BY vendor date DESCENDING.
DELETE ADJACENT DUPLICATES from itab COMPARING vendor.
或者如果示例更复杂,一个简单的 LOOP AT
和 IF
或 AT
在其中 APPENDING
聚合行到一个新的 itab,也将解决它.