操作COBOL数据结构

4

我希望能获取操作表格的相关信息。
我遇到了一段像下面这样的cobol代码,存在一些问题:

01 TABLE-1.  
    05 STRUCT-1 OCCURS 25 TIMES.
        10 VALUE-1 PIC AAA.  
        10 VALUE-2 PIC 9(5)V999.  
    05 NUMBER-OF-OCCURS PIC 99.

当您知道VALUE-1时,如何更新值?(更新VALUE-2)
如何查找值并添加新值?
非常感谢!

3个回答

8

如何查找值/如何更新值

首先,您需要查找要更新的记录(行)。通常情况下,这是通过在表中搜索给定的关键字值来完成的。COBOL提供了几种方法来实现此目的。我建议您从查看COBOL SEARCH语句开始。如果STRUCT-1记录已排序,则可以使用SEARCH ALL,否则必须使用SEARCH或编写自己的搜索循环。为了使用这些技术,您需要在程序的某个地方声明另一个变量,用作STRUCT-1表中的索引(偏移量)。 COBOL提供OCCURS子句上的INDEXED BY短语,以声明特定于给定表的索引(请参见OCCURS

一旦将索引设置为指向要更新的行,您只需将值MOVE到该行内适当的变量中,例如

MOVE 123.456 TO VALUE-2(IDX-1)

其中IDX-1是上述索引。请注意,您可以使用整数或索引变量来指定要更新的行号,不限于使用INDEX类型变量。然而,在使用多维表时,特别是程序频繁引用表时,使用INDEX变量通常更有效率。

如何添加新行

首先,请认识到STRUCT-1恰好包含25行。 COBOL没有动态增加或减少此数量的机制(我听说这将在下一个ISO COBOL标准中可能实现,但不要抱有希望等待它)。从技术上讲,所有25行随时可用。然而,一种常见的约定是按顺序“增长”表,从空表逐行添加到完整表。为了使用此约定,您需要分配一个变量以跟踪上次使用的行号(不要忘记在程序启动时将该变量初始化为零)。在您的示例中,变量NUMBER-OF-OCCURS似乎具有此功能(我没有提到,但是,您需要此变量来限制上面讨论的SEARCH)。

要“添加”一行,只需将NUMBER-OF-OCCURS增加1。注意不要超过表格大小。示例代码可能如下所示:
IF NUMBER-OF-OCCURS < (LENGTH OF TABLE-1 / LENGTH OF STRUCT-1 (1))
   ADD +1 TO NUMBER-OF-OCCURS
ELSE
   table is full, preform some error/recovery routine
END-IF

上述代码避免了显式使用TABLE-1中出现的数量,这反过来可以节省大量维护问题,当/如果OCCURS的数量发生变化时。

请注意底部的注释:这里有一个非常重要的错误——你发现了吗!

现在回到搜索问题。以下代码示例说明了您可能如何进行:

工作区声明:

 01 FOUND-IND  PIC X(1).
    88 FOUND-YES  VALUE 'Y'.
    88 FOUND-NO   VALUE 'N'.
 77 MAX-IDX   USAGE IS INDEX.

 01 TABLE-1.
    05 STRUCT-1 OCCURS 25 TIMES INDEXED BY IDX-1.
       10 VALUE-1 PIC AAA.
       10 VALUE-2 PIC 9(5)V999.
    05 NUMBER-OF-OCCURS PIC 99.

新增内容:

  • FOUND-IND用于指示是否找到了您正在查找的行。88级别给出了特定的值来设置/测试
  • MAX-IDX用于在搜索中设置上限。您可以在上限测试中使用NUMBER-OF-OCCURS,但这将强制进行每次测试的数据类型转换,效率不高
  • IDX-1用作索引(偏移量)进入STRUCT-1表。

个人建议将NUMBER-OF-OCCURS声明为PIC S9(4) BINARY,但您现在拥有的也可以工作。

假设STRUCT-1未排序,NUMBER-OF-OCCURS表示STRUCT-1中当前活动行数,以下是查找值“ABC”时可能编写的SEARCH的示例:

SET FOUND-NO TO TRUE
IF NUMBER-OF-OCCURS > ZERO

   SET IDX-1 TO 1
   SET MAX-IDX TO NUMBER-OF-OCCURS

   SEARCH STRUCT-1
     WHEN IDX-1 > MAX-IDX
       CONTINUE
     WHEN VALUE-1 (IDX-1) = 'ABC'
       SET FOUND-YES TO TRUE
   END-SEARCH
END-IF

IF FOUND-YES
   row found, use IDX-1 to reference the row containing 'ABC'
ELSE
   row not found, IDX-1 does not contain a valid index
END-IF

它的工作方式:

  • 首先假设该行不在表中,将FOUND-NO设置为true。
  • 第一个IF确保在开始搜索之前STRUCT-1中至少有1个活动行(将INDEX设置为零是错误的-因此您需要防范这种情况)。
  • SEARCH在满足第一个SEARCH WHEN子句时终止。这就是为什么在我们没有要搜索的行时可以使用“不执行任何操作”的动词CONTINUE。发现您要查找的值的另一个终止条件是FOUND-YES唯一可以被设置的地方。
  • SEARCH完成时,请检查成功或失败,然后根据情况采取行动。

一些您需要研究的练习:

  • 为什么在SEARCH语句中我不需要编写AT END子句?
  • 为什么在SEARCH语句中我不需要编写子句?
  • 为什么我按照所示顺序编写了WHERE子句?

希望这可以让您朝着正确的方向开始。

编辑

回应您在评论中的问题:我们可以使用NUMBER-OF-OCCURS作为搜索的索引吗。答案是可以,但您需要实现一些不同的规则。当使用NUMBER-OF-OCCURS作为索引时,您不能再将其用于跟踪当前包含有效数据的行数。这意味着您需要另一种机制来标识STRUCT-1中未使用的行。这可能通过使用一个哨兵值(例如LOW-VALUE)初始化未使用的行来实现,而您实际上永远不会想将其放入表中。 SEARCH变为:

SET FOUND-NO TO TRUE 
MOVE 1 TO NUMBER-OF-OCCURS 
SEARCH STRUCT-1 VARYING NUMBER-OF-OCCURS
  WHEN VALUE-1 (NUMBER-OF-OCCURS) = 'ABC' 
    SET FOUND-YES TO TRUE 
END-SEARCH 

上述代码将在表格STRUCT-1的每一行中搜索,以查找您要搜索的值(即ABC),如果该值不在表格中。为了优化,您可以添加第二个WHEN子句,在找到一个标志值后终止搜索:
WHEN VALUE-1 (NUMBER-OF-OCCURS) = LOW-VALUE
   CONTINUE

上述代码假设使用 LOW-VALUE 来识别未使用的行。您还可以从工作存储中删除 IDX-1MAX-IDX,因为此解决方案不需要它们。
使用 NUMBER-OF-OCCURS 作为索引意味着您必须更改插入新值时搜索空行的方式。最简单的方法是使用上面的代码搜索表格而非使用 'ABC' 进行搜索。如果在搜索结束时设置了 FOUND-YES,则 NUMBER-OF-OCCURS 是第一个未使用行的索引。如果设置了 FOUND-NO,则表格已满。
上述代码比我最初建议的代码简单得多。那为什么我要给你更加“复杂”的解决方案呢?更加“复杂”的解决方案效率更高,因为它在运行表格时进行的内部偏移计算和数据类型转换要少得多。它还避免了执行额外的 SEARCH 来查找下一个未使用行。这些效率问题可能不会影响您的应用程序,但如果表格很大并且经常被访问,则应注意搜索表格和强制数据类型转换(例如将 PIC 99 字段转换为索引引用的成本)的性能方面。
注意:我最初的示例中使用 LENGTH OF 特殊寄存器来计算表格是否已满,但其中存在一个非常糟糕的内置假设!LENGTH OF TABLE-1 包括不仅包括 STRUCT-1 表格,还包括 NUMBER-OF-OCCURS。而 NUMBER-OF-OCCURS 的长度小于一个 STRUCT-1 的出现次数,因此由于将结果截断为整数值,一切都可以正常工作。这是代码正确运行但原因错误的很好的例子!要进行正确的计算,您必须将工作存储调整为类似以下内容:
01 TABLE-1.
   05 STRUCT-TABLE. 
      10 STRUCT-1 OCCURS 25 TIMES.
         20 VALUE-1 PIC AAA. 
         20 VALUE-2 PIC 9(5)V999. 
   05 NUMBER-OF-OCCURS PIC 99. 

边界计算将变为:

IF NUMBER-OF-OCCURS < (LENGTH OF STRUCT-TABLE / LENGTH OF STRUCT-1 (1)) 
   ADD +1 TO NUMBER-OF-OCCURS 
ELSE 
   table is full, preform some error/recovery routine 
END-IF 

或者您可以将NUMBER-OF-OCCURS移出TABLE-1记录定义。


+1 用于计算代码中表元素的最大数量。 个人认为可以省略 FOUND-IND 名称,这并不是必要的。我会使用 pic 1 字段,但可能并非所有编译器都能理解二进制字段。 - Kwebble
@Kwebble 说得好,我本可以去掉名为 FOUND-IND 的名称,只保留命名为88级别的内容,但仍然必须提供一个类似X(1)的PICture子句,而Picture子句并不是可选的。 - NealB
你好,非常感谢您提供如此详细的答案!但是我需要更多信息。 我们能否使用NUMBER-OF-OCCURS作为搜索的索引,然后将其用于添加新行? 我的意思是,如果我将其用作索引,这是否会修改NUMBER-OF-OCCURS的值,并且无法像您所写的那样用于添加新行。 - user288830

1

哇...回答好长。假设有一个名为II的数字:

循环执行 II 从1开始 每次增加1

直到 II > 出现次数数量

如果 Value-1(II) = 已知值-1

 Move New-Value-2 to Value-2 (II)

结束-如果

结束-执行


1
为了在工作存储区中填充和修改表格数据,您需要使用下标/索引,您可以在工作存储区中定义它,然后在过程分区中编写处理代码。在这种情况下,您可以使用 perform..until。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接