从内部表中提取唯一值

Lil*_*hal 4 sap abap

从内部表的列或多列中提取唯一值的最有效方法是什么?

Lil*_*hal 7

在ABAP 7.40的SP08版本发布之前,从内部表或itab中提取唯一值的最有效方法如下:

LOOP AT lt_itab ASSIGNING <ls_itab>.
    APPEND <ls_itab>-value TO lt_values.
ENDLOOP.
SORT lt_values.
DELETE ADJACENT DUPLICATES FROM lt_values.
Run Code Online (Sandbox Code Playgroud)

<ls_itab>-value在将其添加到内部表之前检查给定的存在是另一种保证唯一性的方法,但在插入标准表时可能会计算成本更高.对于已排序或散列的目标表,请使用:

LOOP AT lt_itab ASSIGNING <ls_itab>.
    READ TABLE lt_sorted_values WITH KEY table_line = <ls_itab>-value BINARY SEARCH.
    IF sy-subrc <> 0.
        APPEND <ls_itab>-value TO lt_sorted_values.
    ENDIF.
ENDLOOP.
Run Code Online (Sandbox Code Playgroud)

请注意,使用第一种方法但将值插入到虚拟表中后跟a APPEND LINES OF lt_dummy INTO lt_sorted_values 可能会更快,但中间表的大小可能会混淆.


但是, ABAP 7.40支持包08开始,循环提供了一种更好的方法来提取唯一值.正如名称所示,这些功能与SQL类似.例如,以下代码将从内部表中提取唯一的项目编号:GROUP BYGROUP BY

LOOP AT lt_project_data ASSIGNING FIELD-SYMBOL(<ls_grp_proj>)
    GROUP BY ( project = <ls_grp_proj>-proj_number ) ASCENDING
    WITHOUT MEMBERS
    ASSIGNING FIELD-SYMBOL(<ls_grp_unique_proj>).
        APPEND <ls_grp_unique_proj>-project TO lt_unique_projects.
ENDLOOP.
Run Code Online (Sandbox Code Playgroud)

相同的逻辑可被扩展到检索唯一对,如的复合主键EKPO表,EBELN("购买文档", po_nr)和EBELP("采购凭证的项目编号", po_item):

LOOP AT lt_purchasing_document_items ASSIGNING FIELD-SYMBOL(<ls_grp_po>)
    GROUP BY ( number = <ls_grp_po>-po_nr
               item   = <ls_grp_po>-po_item ) ASCENDING
    WITHOUT MEMBERS
    ASSIGNING FIELD-SYMBOL(<ls_grp_po_item>).
        APPEND VALUE #( ebeln = <ls_grp_po_item>-number
                        ebelp = <ls_grp_po_item>-item ) TO lt_unique_po_items.
ENDLOOP.
Run Code Online (Sandbox Code Playgroud)

根据新ABAP 7.40版本的SAP设计人员Horst Keller的说法,GROUP BY循环的性能可能与这些LOOP的手动实现相同.根据如何(有效)实现这样的自定义循环,它甚至可能更快.请注意,对于GROUP BY环路不可用的系统,这些方法将比上面给出的两种方法更快.


请注意,在大多数情况下,查询数据库以返回DISTINCT值将会更快,性能更好,这将使任何使用内部表的ABAP代码失效,尤其是在HANA系统上.


Mar*_*cel 7

如果你有7.40 SP08或更高版本,你只需使用内联语法来填充目标表(不需要LOOP GROUP BY):

DATA: it_unique TYPE STANDARD TABLE OF fieldtype.
it_unique = VALUE #(
  FOR GROUPS value OF <line> IN it_itab
  GROUP BY <line>-field WITHOUT MEMBERS ( value ) ).
Run Code Online (Sandbox Code Playgroud)

这适用于任何类型的目标表.


对于旧版本,请使用:

DATA: it_unique TYPE HASHED TABLE OF fieldtype WITH UNIQUE KEY table_line.
LOOP AT it_itab ASSIGNING <line>.
  INSERT <line>-field INTO TABLE lt_unique.
ENDLOOP.
Run Code Online (Sandbox Code Playgroud)

以上工作也与排序表一起使用.虽然我不建议为此目的使用排序表,除非您确定结果中只有几行.

非零sy-subrcINSERT会被忽略.无需进行两次密钥查找(一次用于存在检查,一次用于插入).


如果目标必须是STANDARD TABLE并且您有一个旧的ABAP堆栈,您也可以使用

DATA: it_unique TYPE STANDARD TABLE OF fieldtype.
LOOP AT it_itab ASSIGNING <line>.
  READ TABLE lt_unique WITH TABLE KEY table_line = <line>-field
    TRANSPORTING NO FIELDS BINARY SEARCH.
  INSERT <line>-field INTO lt_unique INDEX sy-tabix.
ENDLOOP.
Run Code Online (Sandbox Code Playgroud)

这提供了与排序表相同的行为,但具有标准表.这是否比SORT/DELETE ADJACENT DUPLICATES更有效取决于itab中重复条目的数量.存在的重复条目越多,上述解决方案就越快,因为它避免了对目标表的不必要的附加.但另一方面,追加比插入更快.