FOR ALL ENTRIES 的使用为什么需要包括主键

275 阅读3分钟

ABAP 中的 FOR ALL ENTRIES 非常方便,但是如果不正确使用它,也会产生很多问题:数据不一致、重复数据。

基础用法

当我们使用 SELECT 查询语句时,可以使用 FOR ALL ENTIRES, 并在 WHERE 条件中使用数据库表中一个或者多个字段。

IF gt_bseg[] IS NOT INITIAL.  
    SELECT prctr  
           ktext  "利润中心描述  
      INTO CORRESPONDING FIELDS OF TABLE gt_cepct  
      FROM cepct  
      FOR ALL ENTRIES IN gt_bseg  
      WHERE prctr = gt_bseg-prctr  
        AND spras = sy-langu .  
  ENDIF.

如果表中只有少数的主键,我们可以选择这个方法。

但是如果一旦字段多了,这个方法可能就不适用了。

SELECT ryear
         drcrk
         rpmax
         rtcur
         racct
         rbukrs
         rcntr
         kokrs
         hsl01
         hsl02
         hsl03
         hsl04
         hsl05
         hsl06
         hsl07
         hsl08
         hsl09
         hsl10
         hsl11
         hsl12
    FROM faglflext
    INTO TABLE lt_fagl
    FOR ALL ENTRIES IN lt_skb1
    WHERE ryear IN lr_gjahr
    AND   racct  = lt_skb1-saknr
    AND   rbukrs = lt_skb1-bukrs.

由于这个查询没有所有的关键字段,当你试图将其与一些标准交易 FAGLB03 进行对账时,你会遇到问题。当你在不同时期使用相同的 CC 为相同的 GL 过账时,问题就会发生。在这种情况下,系统将只带来一个记录,而不是多个记录。另一方面,标准交易会让你得到的所有条目都有所不同。

当你调试 std 事务并到达 SELECT 时,你会想,这和我的查询一样。那为什么我的查询不工作呢?所以你从 ITAB 中下载数据--你的程序和 STD 事务。你将它们进行比较,你会注意到有几个条目肯定丢失了。经过几轮 VLOOKUP 和 excel 中的比较,你突然意识到 FOR ALL ENTRIES 丢了几个条目。这时,你已经是 Excel 的专家了。

为了解决这个问题,你会意识到你需要在 SELECT 中包含更多的关键字段。下一个障碍是向你的职能部门的同事和你的用户解释为什么它不能工作。

如果这个程序不是你开发的,我可以想象,当你意识到根本原因时,你有多恨那个人。一个愚蠢的错误! 从好的方面看,你现在是Excel专家了~

为什么需要主键

为了提高性能,你肯定希望在FOR ALL ENTIRES 的 ITAB 里有唯一的值。如果你不传递唯一的值,DB 将为每个重复的值重新选择记录。最后,DB 将删除重复的记录并给你结果集。

如果你在 SELECT 查询的选择字段中没有关键字段,那么这种去除重复的做法会造成数据不一致的情况。如果你认为你的所有字段都会构成唯一值,而不包括关键字段,你就会在将来招致麻烦。

添加表的键字段将确保所有选择的记录是唯一的。如果 SELECT 是一个联接,确保你包括联接中包括的所有表的所有关键字段。

TYPES:
  BEGIN OF ty_t100,
    arbgb TYPE t100-arbgb,
    msgnr TYPE t100-msgnr,
    text  TYPE t100-text,
  END   OF ty_t100.
 
DATA: t_ids       TYPE STANDARD TABLE OF t100-msgnr.
DATA: t_t100_all  TYPE STANDARD TABLE OF t100.
DATA: t_t100      TYPE STANDARD TABLE OF ty_t100.
 
APPEND  '001' TO t_ids.
APPEND  '002' TO t_ids.
 
IF t_ids IS NOT INITIAL.
  SELECT  arbgb
          msgnr
          text           "comment to see more records are dropping
    INTO TABLE t_t100
    FROM t100
    FOR ALL ENTRIES IN t_ids
    WHERE arbgb LIKE '0%'
    AND   msgnr = t_ids-TABLE_LINE.
  WRITE: / 'Without All Key Fields', sy-dbcnt.
ENDIF.

如果你把第一个查询中的 TEXT 字段注释掉,你会看到更多的记录被丢弃。这是因为,DB 只保留唯一的记录。DB 会将整个记录与所有的记录进行比较,然后丢弃这些行。就像 DELETE ADJACENT DUPLICATES FROM itab COMPARING ALL FIELDS

总结

当你使用 FOR ALL ENTRIES 时,连同其他事情,你肯定想确保你在内部表中有所有的关键字段,你也在选择它们,以避免数据不一致。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情