通过分组在 ABAP 内部表中查找重复项

Posted

技术标签:

【中文标题】通过分组在 ABAP 内部表中查找重复项【英文标题】:Finding duplicates in ABAP internal table via grouping 【发布时间】:2022-01-07 04:53:19 【问题描述】:

我们都知道these excellent ABAP statements 允许在单行中找到唯一值:

it_unique = VALUE #( FOR GROUPS value OF <line> IN it_itab 
                     GROUP BY <line>-field WITHOUT MEMBERS ( value ) ).

但是提取重复项呢?可以为该任务使用GROUP BY 语法吗?或者,表格解析在这里更有用?

我发现的唯一(虽然不是很优雅)的方法是:

LOOP AT lt_marc ASSIGNING FIELD-SYMBOL(<fs_marc>) GROUP BY ( matnr = <fs_marc>-matnr 
                                                             werks = <fs_marc>-werks )
                                                  ASSIGNING FIELD-SYMBOL(<group>).
  members = VALUE #( FOR m IN GROUP <group> ( m ) ).

  IF lines( members ) > 1.
    "throw error
  ENDIF.

ENDLOOP.

有没有更漂亮的方法可以通过任意键查找重复项?

【问题讨论】:

【参考方案1】:

所以,我只是把它作为答案,因为我们和弗洛里安无法想出更好的东西。 如果有人能够改进它,那就去做吧。

TYPES tt_materials TYPE STANDARD TABLE OF marc WITH DEFAULT KEY. 

DATA duplicates TYPE tt_materials. 
LOOP AT materials INTO DATA(material) 
GROUP BY ( id = material-matnr 
           status = material-pstat 
           size = GROUP SIZE ) 
ASCENDING REFERENCE INTO DATA(group_ref). 

CHECK group_ref->*-size > 1. 
duplicates = VALUE tt_materials( BASE duplicates FOR <status> IN GROUP group_ref ( <status> ) ). 

ENDLOOP.

【讨论】:

【参考方案2】:

给定

TYPES: BEGIN OF key_row_type,
         matnr TYPE matnr,
         werks TYPE werks_d,
       END OF key_row_type.
TYPES key_table_type TYPE
  STANDARD TABLE OF key_row_type
  WITH DEFAULT KEY.

TYPES: BEGIN OF group_row_type,
         matnr TYPE matnr,
         werks TYPE werks_d,
         size  TYPE i,
       END OF group_row_type.
TYPES group_table_type TYPE
  STANDARD TABLE OF group_row_type
  WITH DEFAULT KEY.

TYPES tt_materials TYPE STANDARD TABLE OF marc WITH DEFAULT KEY.
DATA(materials) = VALUE tt_materials(
  ( matnr = '23' werks = 'US' maabc = 'B' )
  ( matnr = '42' werks = 'DE' maabc = 'A' )
  ( matnr = '42' werks = 'DE' maabc = 'B' ) ).

什么时候

DATA(duplicates) =
  VALUE key_table_type(
    FOR key IN VALUE group_table_type(
      FOR GROUPS group OF material IN materials
      GROUP BY ( matnr = material-matnr
                 werks = material-werks
                 size  = GROUP SIZE )
      WITHOUT MEMBERS ( group ) )
    WHERE ( size > 1 )
    ( matnr = key-matnr
      werks = key-werks ) ).

然后

cl_abap_unit_assert=>assert_equals(
    act = duplicates
    exp = VALUE tt_materials( ( matnr = '42' werks = 'DE') ) ).

这个解决方案的可读性太差了,你应该只在一个带有暴露名称的方法中使用它,比如collect_duplicate_keys

另请注意,语句的长度会随着关键字段数量的增加而增加,因为添加 GROUP SIZE 需要将关键字段一一列为简单类型的列表。

【讨论】:

whether you want the table of extracted duplicates to contain duplicates itself, or reduce them to unique keys,由于我的问题中给出了后者的解决方案,您可能猜到我想要前者:) 我想在不影响初始表的情况下将重复项提取到单独的表中 您的问题实际上只提供了“如果我的表包含重复项,我该如何抛出错误”的解决方案。 it_unique 表检查第一个sn-p,它正是你的第一个用例,你已经从答案中删除了 好的。更新了答案。 Readability of this solution is so bad ,是的,这太可怕了 :) 您的第一个变体要好得多。我做了一个solution based on it。我们可以让它更简洁吗?除了显式检查循环内,我们可以排除唯一组(大小=1)吗?【参考方案3】:

经典呢?我不确定它们是否已被弃用,但我的第一个想法是要创建一个表克隆,在其上删除 ADJACENT-DUPLICATES,然后比较两行()... 我会渴望阅读新的选项。

【讨论】:

经典不方便,因为它需要删除,所以需要额外的临时标签来完成任务。如果表包含数百万条记录,那就不酷了。 好的,我明白你的意思,我真的很感激 - 并且喜欢 - 它。所以,答案将是使用我不熟悉的新句子。我将把我的答案保留在这里而不是删除它,以防止更多的老人写相同的答案;) 是的。 VALUE 操作符的美妙之处在于它从初始构造新表,并且初始表是untouched 收集仍然是一个糟糕的选择?如果您无论如何要创建一个新的无用表,也许您可​​以将您的“关键”字段和值 1 收集到该新表中,并在任何行达到值 2 时引发您的错误......再次,我不确定如果我错了,但在我们等待更好的答案时,这次谈话很有用(至少对我来说;)) 如何通过COLLECT 引发错误?如果违反 COLLECT 结构中的主键,它只会导致 non-handleable 异常(短转储)。不酷:)

以上是关于通过分组在 ABAP 内部表中查找重复项的主要内容,如果未能解决你的问题,请参考以下文章

如何通过abap中的XSLT程序读取XML文件的属性

Mongoose 聚合内部查找按字段分组

查找重复项,然后使用主表中的 id 更新表,然后删除表中的记录

如何获取在 SQL Server 内部数据库的不同表中重复的列[重复]

如何编写 SQL 查询以查找表中的重复项

SQL 查找具有多个字段的重复项(没有唯一 ID)