Grouping SQL中具有子句的条件itab分组

Grouping SQL中具有子句的条件itab分组,grouping,abap,having,internal-tables,Grouping,Abap,Having,Internal Tables,这是对的后续问题,但我希望根据某些条件处理组,而不是聚合,并且无法找到正确的语法。如果组中至少有一个成员具有“已删除”状态,则我需要排除包含状态为“已删除”的文档的组 到目前为止,我尝试了组…没有成员,循环…组,减少,这就是我最终得到的解决方案 DATA(lt_valid_doc) = VALUE tt_struct( FOR ls_valid IN VALUE tt_struct( FOR GROUPS <group_key> OF <

这是对的后续问题,但我希望根据某些条件处理组,而不是聚合,并且无法找到正确的语法。如果组中至少有一个成员具有“已删除”状态,则我需要排除包含状态为“已删除”的文档的组

到目前为止,我尝试了
组…没有成员
循环…组
减少
,这就是我最终得到的解决方案

DATA(lt_valid_doc) = VALUE tt_struct( 
      FOR ls_valid IN VALUE tt_struct( 
             FOR GROUPS <group_key> OF <wa> IN lt_ilot
             GROUP BY ( guid = <wa>-guid guid2 = <wa>-guid2 ) ASCENDING
             LET not_deleted = REDUCE #( INIT valid TYPE t_ref_s_struct
                                         FOR <m> IN GROUP <group_key>
                                         NEXT valid = COND #( 
                                               WHEN valid IS NOT BOUND OR <m>-stat = 'I1040' 
                                               THEN REF #( <m> ) ELSE valid ) )
             IN ( not_deleted->* ) )
      WHERE ( status NE 'I1040' ) 
      ( ls_valid ) ).
输入行

bukrs belnr       gjahr buzei xnegp
1000  0100000001  2019  1 
1000  0100000001  2019  2
1000  0100000003  2019  1
1000  0100000003  2019  2
1000  0100000004  2019  1
1000  0100000004  2019  2     X
文件0100000004已反转行,因此结果应为

bukrs belnr       gjahr buzei xnegp
1000  0100000001  2019   
1000  0100000003  2019

这里有一个不重复选择的解决方案,但还有一个问题,那真的“更好”吗

如果一组行包含一条状态为“I1040”的行,则解决方案基于生成空行,而不是保留不需要的行。我不确定,但也许另一个类似的解决方案可以保留对该行的引用(
not_deleted
),并添加一个辅助变量以了解引用是否要保留。我发现使用表索引更直观(
INDEX-INTO
),但如果
tt\u-struct
是散列表类型,这可能不起作用

我为代码提供了一个ABAP单元测试,以便您可以自己快速地进行测试

CLASS ltc_main DEFINITION FOR TESTING
      DURATION SHORT RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    METHODS test FOR TESTING.
    METHODS cut.
    TYPES : BEGIN OF ty_struct,
              guid TYPE string,
              stat TYPE string,
            END OF ty_struct,
            tt_struct      TYPE STANDARD TABLE OF ty_struct WITH EMPTY KEY,
            t_ref_s_struct TYPE REF TO ty_struct.
    DATA: lt_ilot      TYPE tt_struct,
          lt_valid_doc TYPE tt_struct.
ENDCLASS.

CLASS ltc_main IMPLEMENTATION.
  METHOD cut.
    lt_valid_doc = VALUE #(
          FOR ls_valid IN VALUE tt_struct(
                 FOR GROUPS <group_key> OF <wa> IN lt_ilot
                 GROUP BY ( guid = <wa>-guid ) ASCENDING
                 LET x1 = REDUCE #(
                        INIT x2 = 0
                        FOR <m> IN GROUP <group_key> INDEX INTO x3
                        NEXT x2 = COND #(
                              WHEN <m>-stat = 'I1040' THEN -1
                              ELSE COND #( WHEN x2 <> 0 THEN x2 ELSE x3 ) ) )
                 IN ( COND #( WHEN x1 <> -1 THEN lt_ilot[ x1 ] ) ) )
          WHERE ( table_line IS NOT INITIAL )
          ( ls_valid ) ).
  ENDMETHOD.

  METHOD test.

    lt_ilot = VALUE #(
        ( guid = 'A' stat = 'I1000' )
        ( guid = 'A' stat = 'I1040' )
        ( guid = 'B' stat = 'I1020' )
        ( guid = 'C' stat = 'I1040' )
        ( guid = 'D' stat = 'I1040' )
        ( guid = 'D' stat = 'I1000' ) ).

    cut( ).

    cl_abap_unit_assert=>assert_equals( act = lt_valid_doc
          exp = VALUE tt_struct( ( guid = 'B' stat = 'I1020' ) ) ).

  ENDMETHOD.
ENDCLASS.
CLASS ltc\u测试的主要定义
持续时间短,风险等级无害。
私人部分。
测试方法。
方法切割。
类型:ty_结构的开头,
guid类型字符串,
stat类型字符串,
结构的末尾,
带空键的ty_结构的tt_结构类型标准表,
t_ref_s_结构类型ref TO ty_结构。
数据:lt ilot类型tt结构,
lt\u有效文档类型tt\u结构。
末级。
类ltc_主实现。
方法切割。
lt\u valid\u doc=值#(
对于ls_,在值tt_结构中有效(
对于lt\u ilot中的组
分组依据(guid=-guid)升序
设x1=REDUCE#(
初始x2=0
对于组内索引到x3
下一个x2=秒#(
当-stat='I1040'时,则为-1
ELSE COND#(当x2 0时,则x2 ELSE x3)))
IN(COND#(当x1-1时,则lt_ilot[x1]))
其中(表_行不是首字母)
(ls_有效)。
ENDMETHOD。
方法试验。
lt_ilot=值#(
(guid='A'stat='I1000')
(guid='A'stat='I1040')
(guid='B'状态='I1020')
(guid='C'统计='I1040')
(guid='D'stat='I1040')
(guid='D'stat='I1000'))。
切()。
cl\U abap\U单元断言=>断言等于(act=lt\U有效文档
exp=VALUE tt_struct((guid='B'stat='I1020'))。
ENDMETHOD。
末级。

以下解决方案可能不是最漂亮的,但很简单。如果一个成员符合某个条件,那么我更容易删除整个组,而不是在所有成员都不符合条件的情况下添加整个组。只是个主意

TYPES : BEGIN OF ty_struct,
          guid TYPE string,
          stat TYPE string,
        END OF ty_struct,
        tt_struct TYPE STANDARD TABLE OF ty_struct WITH EMPTY KEY.


DATA(lt_ilot) = VALUE tt_struct(
    ( guid = 'A' stat = 'I1000' )
    ( guid = 'A' stat = 'I1040' )
    ( guid = 'B' stat = 'I1020' )
    ( guid = 'C' stat = 'I1040' )
    ( guid = 'D' stat = 'I1040' )
    ( guid = 'D' stat = 'I1000' )).

LOOP AT lt_ilot INTO DATA(ls_ilot) WHERE stat = 'I1040'.
  DELETE lt_ilot WHERE guid = ls_ilot-guid.
ENDLOOP.

我真的希望这是某种个人测试用例,不要在生产环境中使用这种编码。如果我想了解你想要实现什么,只看编码,我会恨你;)

轻松解决此问题的关键是对表进行排序,以便删除条件始终位于要处理的组的第一行:

解决方案1 具有唯一列表的输出:

DATA: lt_bseg TYPE STANDARD TABLE OF t_s_bseg.

SORT lt_bseg BY belnr xnegp DESCENDING.
DELETE ADJACENT DUPLICATES FROM lt_bseg COMPARING belnr.
DELETE lt_bseg WHERE xnegp = abap_true.
DATA: lt_bseg TYPE STANDARD TABLE OF t_s_bseg,
      lf_prev_belnr TYPE belnr,
      lf_delete TYPE char1.

SORT lt_bseg BY belnr xnegp DESCENDING.

LOOP AT lt_bseg ASSIGNING FIELD-SYMBOL(<ls_bseg>).

    IF <ls_bseg>-belnr <> lf_prev_belnr.
        lf_delete = <ls_bseg>-xnegp.
        lf_prev_belnr = <ls_bseg>-belnr.
    ENDIF.

    IF lf_delete = abap_true.
        DELETE lt_bseg.
    ENDIF.

ENDLOOP.
解决方案2

输出非唯一列表时:

DATA: lt_bseg TYPE STANDARD TABLE OF t_s_bseg.

SORT lt_bseg BY belnr xnegp DESCENDING.
DELETE ADJACENT DUPLICATES FROM lt_bseg COMPARING belnr.
DELETE lt_bseg WHERE xnegp = abap_true.
DATA: lt_bseg TYPE STANDARD TABLE OF t_s_bseg,
      lf_prev_belnr TYPE belnr,
      lf_delete TYPE char1.

SORT lt_bseg BY belnr xnegp DESCENDING.

LOOP AT lt_bseg ASSIGNING FIELD-SYMBOL(<ls_bseg>).

    IF <ls_bseg>-belnr <> lf_prev_belnr.
        lf_delete = <ls_bseg>-xnegp.
        lf_prev_belnr = <ls_bseg>-belnr.
    ENDIF.

    IF lf_delete = abap_true.
        DELETE lt_bseg.
    ENDIF.

ENDLOOP.
数据:t\U bseg的lt\U bseg类型标准表,
左前安全带类型安全带,
如果删除类型char1。
按belnr xnegp降序对lt_bseg进行排序。
在lt_bseg赋值字段-SYMBOL()处循环。
如果-带左前带左前带。
lf_delete=-xnegp。
如果上一个贝尔纳=-贝尔纳。
恩迪夫。
如果lf_delete=abap_true。
删除lt_bseg。
恩迪夫。
结束循环。

如果这是一个包含所有依赖项的可编译示例,那会有很大帮助。@Jagger添加了基于FI的示例,我的案例来自SRM,因此几乎无法被每个人复制。您的解决方案不包括分组,可以使用相同guid的几行代码。如果我正确理解OP的请求,预期的结果是唯一的行“B I1020”(所有来自I1040组的行都将被删除)。
我恨你
我真的不在乎:)它有效,这是最主要的。顺便说一句,你的解决方案1只适用于具有二进制字段(如XNEGP)的原始情况,基于字符串的状态为I1040的主要示例不适用于排序。哇!我对REDUCE语法不是很有经验,这对我来说很新奇,它可以递归地构造带条件的行,比如
NEXT x2=COND#(当stat=…然后-1 ELSE COND#(当x2 0然后x2)
。总的来说,我认为你的解决方案不如我的解决方案可读性和简洁),尽管它只过滤了一次状态,尽管如此,它还是无法摆脱嵌套表结构
x1-1
条件实际上与第二个状态过滤器相同,因此没有任何增益,性能也没有任何可读性。