通过分组在 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 内部表中查找重复项的主要内容,如果未能解决你的问题,请参考以下文章
查找重复项,然后使用主表中的 id 更新表,然后删除表中的记录