繁体   English   中英

从表中选择列值具有“最高优先级”的行

[英]Select row from table where column value has "highest priority"

我有一个包含 DOC1、DOC2 和 CLIENT 列的数据库表。 我试图为每个 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. 

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

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

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

如果我没有理解这个权利,你要选择输出每个客户端只有一条线路,选择根据这些DOC1优先从原始表行。

这样的选择是不可能的。

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

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

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

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

由于您的 doc1 优先级值实际上是 6,所以这应该有效。

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.

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

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

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

下面的代码获取匹配列 CARRID 的每个不同值的SFLIGHT行(相当于您问题中的 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 规则)之后完成。
  • 如果SFLIGHT几行具有相同的 CARRID 和 PAYMENTSUM 值,则随机选择其中一行(经典 SQL 规则)。
  • 它适用于 ABAP 7.52,但可能不适用于旧版本。
  • 对于有更复杂请求的未来访问者,该解决方案可能很快变得无法适应。
  • 在“原生 SQL”(直接使用数据库 SQL)中可能有一些更简单的解决方案,比如使用SELECT ... FROM ( SELECT ... ) (不允许到 ABAP SQL 7.53)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM