1

我有一个包含 DOC1、DOC2 和 CLIENT 列的数据库表。我正在尝试为每个客户选择一行,其 DOC1 列具有最高优先级,基于以下顺序,从最高到最低优先级:ITCI > ITPP > ITPS > ITPT。

这是一个例子。

输入

DOC1  DOC2  CLIENT
ITCI  GG319  101
ITPS  YB311  102  
ITPT  GG319  101
ITPP  YB311  102

输出

目标表应该有 CLIENT 具有唯一键,我必须添加两列 DOC1 和 DOC2,方法是采用具有最高优先级的 DOC1 的行。

CLIENT DOC2 DOC1
101   GG319 ITCI
102   YB311 ITPP

我编写了一个 select single in end 例程,但出现语法错误:

Select single doc1  doc2 (W_doc1, W_doc2)
        FROM /BI0/Pdoctax
        WHERE  client eq <RESULT_FIELDS>-client. 
4

4 回答 4

1

由于您从最高到最低的优先级顺序完全类似于字母顺序,您只需要使用 GROUP BY 和 MIN 聚合:

SELECT client, MIN( doc2 ) AS doc2, MIN( doc1 ) AS doc1
INTO TABLE @DATA(itab)
FROM /BI0/Pdoctax
GROUP BY client.

在排序规则不那么原始的更复杂的情况下,您可以使用CASE子句。

于 2019-07-25T19:08:02.150 回答
0

由于您的 doc1 优先级值实际上是六个,因此应该可以。

SELECT b~client,
       coalesce( p1~doc1, p2~doc1, p3~doc1, p4~doc1, p5~doc1, p6~doc1 ),
       coalesce( p1~doc2, p2~doc2, p3~doc2, p4~doc2, p5~doc2, p6~doc2 )
  FROM /bi0/pdoctax AS b
                 LEFT OUTER JOIN /bi0/pdoctax AS p1
                 ON  p1~client = b~client
                 AND p1~doc1   = 'ITCI'
                 LEFT OUTER JOIN /bi0/pdoctax AS p2
                 ON  p2~client = b~client
                 AND p2~doc1   = 'ITPS'
                 LEFT OUTER JOIN /bi0/pdoctax AS p3
                 ON  p3~client = b~client
                 AND p3~doc1   = 'ITPT'
                 LEFT OUTER JOIN /bi0/pdoctax AS p4
                 ON  p4~client = b~client
                 AND p4~doc1   = 'ITPT'
                 LEFT OUTER JOIN /bi0/pdoctax AS p5
                 ON  p4~client = b~client
                 AND p4~doc1   = 'P5'
                 LEFT OUTER JOIN /bi0/pdoctax AS p6
                 ON  p4~client = b~client
                 AND p4~doc1   = 'P6'
  WHERE b~client = @<result_fields>-client
   INTO @DATA(ls_doctax).

我假设您正在寻找在单个 SELECT 语句中执行此操作的答案,否则您可以循环:

  DATA lt_priorities TYPE STANDARD TABLE OF /bi0/pdoctax-doc1.
  lt_priorities = VALUE #( ( 'ITCI' ) ( 'ITPS' ) ( 'ITPT' ) ( 'ITPP' ) ( 'P500' ) ( 'P600' ) ).

  SELECT b~client,
         doc1,
         doc2
    FROM /bi0/pdoctax AS b
   WHERE b~client = @<result_fields>-client
   ORDER BY doc1 ASCENDING
    INTO TABLE @DATA(lt_doctax).

  DATA ls_doctax_filtered LIKE LINE OF lt_doctax.

  LOOP AT lt_priorities ASSIGNING FIELD-SYMBOL(<fs_priority>).
    READ TABLE lt_doctax ASSIGNING FIELD-SYMBOL(<fs_doctax>)
      WITH KEY doc1 = <fs_priority> BINARY SEARCH.
    IF sy-subrc = 0.
      ls_doctax_filtered = <fs_doctax>.
*     --->
      EXIT.
    ENDIF.
  ENDLOOP.
于 2019-07-26T10:46:03.000 回答
0

如果我理解正确,您希望 select 为每个 CLIENT 仅输出一行,根据这些 DOC1 优先级从原始表中选择行。

这样的选择是不可能的。

在我的脑海中,这些是我想出的可能性,但可能还有更多。根据您的情况,您必须确定哪一个最适合您的需求。

  1. 您可以选择所有内容,对其进行循环并使用 IF 条件等创建格式。

  2. 如果您真的只有这 4 种 DOC1 可能性,您可以选择所有内容,按 CLIENT 和 DOC1 对内部表进行排序,然后删除仅比较 CLIENT 的相邻重复项。这会起作用,因为“ITCI >ITPP >ITPS>ITPT”是按字母顺序排列的。

  3. 同样,如果您只有这 4 种 DOC1 可能性,那么您可以一个接一个地选择它们,检查是否仍然缺少 CLIENTS。

于 2019-07-25T09:53:07.957 回答
0

这是使用 ABAP 7.52 的“简单”解决方案。

我为测试使用了另一个示例,以便任何人都可以使用它:我使用了SFLIGHT随任何 ABAP 安装提供的演示表。如果表为空,则运行程序SAPBC_DATA_GENERATOR生成数据。

正如其他人已经提到的,假设您的优先级是基于字母顺序的,因此MIN可以使用聚合函数。

下面的代码获取SFLIGHT与 CARRID 列的每个不同值相匹配的行(相当于您问题中的 CLIENT)及其在 PAYMENTSUM (DOC1) 列中的最小值(都在EXISTS子查询内):

SELECT carrid, fldate AS doc2, paymentsum AS doc1
FROM sflight AS a
WHERE EXISTS (
        SELECT carrid
        FROM sflight
        WHERE carrid = a~carrid
        GROUP BY carrid
        HAVING MIN( paymentsum ) = a~paymentsum )
INTO TABLE @DATA(itab).

数据库表的内容SFLIGHT(通过 SE16/突出显示的预期结果): 在此处输入图像描述

内部表的内容itab(通过调试/按预期): 在此处输入图像描述

关于 ABAP SQL 代码的注意事项:

  • 对聚合结果的任何选择只能在 HAVING 之后完成,而不是在 WHERE 之后(经典 SQL 规则)。
  • 如果 CARRID 和 PAYMENTSUM 的几行SFLIGHT具有相同的值,则随机选择其中一行(经典 SQL 规则)。
  • 它适用于 ABAP 7.52,但可能不适用于旧版本。
  • 对于具有更复杂请求的未来访问者,该解决方案可能很快变得无法适应。
  • 在“本机 SQL”(直接使用数据库 SQL)中可能有一些更简单的解决方案,例如使用SELECT ... FROM ( SELECT ... )(直到 ABAP SQL 7.53 才允许)
于 2019-07-26T18:54:42.263 回答