我希望能获取操作表格的相关信息。
我遇到了一段像下面这样的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)
如何查找值并添加新值?
非常感谢!
我希望能获取操作表格的相关信息。
我遇到了一段像下面这样的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)
如何查找值并添加新值?
非常感谢!
如何查找值/如何更新值
首先,您需要查找要更新的记录(行)。通常情况下,这是通过在表中搜索给定的关键字值来完成的。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-1
和 MAX-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
记录定义。
哇...回答好长。假设有一个名为II的数字:
循环执行 II 从1开始 每次增加1
直到 II > 出现次数数量
如果 Value-1(II) = 已知值-1
Move New-Value-2 to Value-2 (II)
结束-如果
结束-执行