分组和循环

GROUP 和 LOOP 命令提供了两种重复执行一系列命令的方式。GROUP 针对每个记录执行一个或多个命令的单个迭代。LOOP 针对单个记录执行一系列命令的多个迭代,并且只能在 GROUP 块内部使用。

GROUP 简单示例

您具有一个名为 Ap_Trans 的发票数据表。使用该数据,您需要计算发票金额的运行合计:

Vendor_Number Vendor_Name Invoice_Number 日期 金额
11663 More Power Industries 5981807 2000-11-17 618.30
13808 NOVATECH Wholesale 2275301 2000-11-17 6705.12
12433 Koro International 6585673 2000-11-17 7955.46

为了计算该金额,您使用 GROUP 命令。在 GROUP 的每个迭代内部,您:

  1. 计算截止到当前记录的运行合计。
  2. 将发票编号、金额、日期和运行合计提取至结果表。
OPEN Ap_Trans

COMMENT 将运行合计的初始值设置为零 END
ASSIGN v_running_total = 0.00

COMMENT 对该表中的每个记录进行遍历处理,然后计算并提取运行合计 END
GROUP
  ASSIGN v_running_total = v_running_total + Amount
  EXTRACT Invoice_Number, Amount, Date, v_running_total AS "Running total" TO results1
END

当该脚本运行时,将从上到下,针对表中的每个记录处理 GROUP 块内部的命令,并且计算和提取运行合计。如果我们能够在 GROUP 运行时在其中穿行,则会看到以下过程:

GROUP 的第一个迭代:运行合计 = 0.00 + 618.30

GROUP 将第一个记录的发票金额添加到初始运行合计 0.00 并且将域提取至结果表:

Vendor_Number Vendor_Name Invoice_Number 日期 金额
11663 More Power Industries 5981807 2000-11-17 618.30
13808 NOVATECH Wholesale 2275301 2000-11-17 6705.12
12433 Koro International 6585673 2000-11-17 7955.46

GROUP 的第二次迭代:运行合计 = 618.30 + 6705.12

GROUP 块将第二个记录的发票金额添加到新的运行合计 618.30 并且将域提取至结果表:

Vendor_Number Vendor_Name Invoice_Number 日期 金额
11663 More Power Industries 5981807 2000-11-17 618.30
13808 NOVATECH Wholesale 2275301 2000-11-17 6705.12
12433 Koro International 6585673 2000-11-17 7955.46

GROUP 的第三次迭代:运行合计 = 7323.42 + 7955.46

GROUP 块将第三个记录的发票金额添加到新的运行合计 7323.42 并且将域提取至结果表:

Vendor_Number Vendor_Name Invoice_Number 日期 金额
11663 More Power Industries 5981807 2000-11-17 618.30
13808 NOVATECH Wholesale 2275301 2000-11-17 6705.12
12433 Koro International 6585673 2000-11-17 7955.46

最终的结果表

在 GROUP 已处理该表中的最后一个记录后,您将拥有以下结果表:

Invoice_Number 金额 日期 Running_total
5981807 618.30 2000-11-17 618.30
2275301 6705.12 2000-11-17 7323.42
6585673 7955.46 2000-11-17 15278.88

使用 GROUP IF 处理不同的情况

使用如上所示的相同 Ap_Trans 表,您现在需要计算三种发票的运行合计:

  • 高值(大于或者等于 1000.00)
  • 中值(介于 100.00 和 1000.00 之间)
  • 低值(小于 100.00)

GROUP 命令提供了一个 IF/ELSE 结构以处理不同的情况。您提供了要测试的条件表达式,并且如果某个记录评估为真,则块内部的命令会运行。

如何测试情况

情况被从上到下进行测试,并且一个记录只能由一个 IF/ELSE 块处理。对于该记录而言,第一个评估为真的情况是处理该记录的情况:

  1. 当 GROUP 处理第一个记录时,它会根据第一个 IF 条件 (Amount >= 1000) 来测试它。如果该条件评估为真,则此情况的代码会运行,并且不会再测试其他情况。
  2. 如果第一个情况评估为假,则会测试下一个 ELSE IF 条件 (Amount >= 100)。同样,如果该测试评估为真,则此情况的代码会运行,并且不会测试其他情况。
  3. 最后,如果 IF 或 ELSE IF 情况中没有一个情况评估为真,则 ELSE 块中的默认情况会处理该记录。

说明

如果某个记录对于一种以上的情况皆评估为真,则该记录只被测试它的第一个 IF/ELSE 块处理。记录永远不会被 GROUP 命令中一个以上的 IF/ELSE 块处理。

OPEN Ap_Trans

COMMENT 设置运行合计的初始值 END
ASSIGN v_running_total_hi = 0.00
ASSIGN v_running_total_med = 0.00
ASSIGN v_running_total_low = 0.00

COMMENT 根据发票金额的不同,使用 GROUP IF 运行不同的 ASSIGN 和 EXTRACT 命令 END
GROUP IF Amount >= 1000
  ASSIGN v_running_total_hi = v_running_total_hi + Amount
  EXTRACT Invoice_Number, Amount, Date, v_running_total_hi AS "Running total" TO results_hi
ELSE IF Amount >= 100
  ASSIGN v_running_total_med = v_running_total_med + Amount
  EXTRACT Invoice_Number, Amount, Date, v_running_total_med AS "Running total" TO results_med
ELSE
  ASSIGN v_running_total_low = v_running_total_low + Amount
  EXTRACT Invoice_Number, Amount, Date, v_running_total_low AS "Running total" TO results_low
END

当该脚本运行时, GROUP 命令会测试每个记录的发票金额。根据金额的不同,将使用记录来更新三个运行合计(低、中、高)之一并且生成三个结果表。

GROUP 内部的 LOOP

使用 GROUP 处理表中的记录时,您可以一个使用 LOOP 命令对单个记录多次执行一系列命令。LOOP 是发生在 GROUP 迭代内部的辅助迭代,它会运行到您指定的测试条件评估为假为止。

使用 LOOP 拆分域

您具有以下包含发票数据的表,并且需要按部门隔离发票金额的特定信息。一个发票可能与一个以上的部门相关,部门代码以逗号分隔格式存储在该表中:

Vendor_Number Invoice_Number 日期 金额 Dept_Code
11663 5981807 2000-11-17 618.30 CCD,RDR
13808 2275301 2000-11-17 6705.12 CCD
12433 6585673 2000-11-17 7955.46 CCD,LMO,RDR

要按部门提取发票金额,您:

  1. 使用 GROUP 命令逐个记录地处理该表。
  2. 计算与每个记录相关联的部门的数量 (n)。
  3. 使用 LOOP 命令在该记录上迭代 n 次,以提取与该记录相关联的每个部门的数据。

说明

您必须在 LOOP 内部递增 v_counter 变量。如果您不这样做,则 WHILE 测试总是评估为真,脚本会进入无限循环。您可以在您的脚本中包括一个 SET LOOP 命令以防备无限循环。有关详细信息,请参阅 SET LOOP 命令

COMMENT
使用 GROUP 可统计每个部门代码字段中的逗号个数,作为识别有多少个部门与该记录相关联的方式
对于该域中的每个代码,对每个记录执行“LOOP”命令,并且在该循环的每次迭代中,将带有单个代码的记录提取至 result1 表
END

GROUP
v_department_count = OCCURS(Dept_Code,',')
v_counter = 0
LOOP WHILE v_counter <= v_department_count
v_dept = SPLIT(Dept_Code, ',', (v_counter + 1))
EXTRACT FIELDS Invoice_Number, Amount, v_dept AS "Department" TO result1
v_counter = v_counter + 1
END
END

当该脚本运行时,将从上到下,针对该表中的每个记录处理 GROUP 块内部的命令。对于每个记录,LOOP 命令都会针对逗号分隔列表中的每个部门代码在该记录上迭代一次,然后提取一个记录。如果我们能够在 GROUP 和 LOOP 运行时在其中穿行,则会看到以下过程:

GROUP 的第一次迭代:LOOP 的两次迭代

Vendor_Number Invoice_Number 日期 金额 Dept_Code
11663 5981807 2000-11-17 618.30 CCD,RDR
13808 2275301 2000-11-17 6705.12 CCD
12433 6585673 2000-11-17 7955.46 CCD,LMO,RDR

对于该表中的第一个记录,v_department_count 的值是 1,因此 LOOP 迭代两次:

  1. 对于 LOOP 的第一次迭代:
    • v_counter = 0
    • v_depart = CCD

    提取以下记录,并且 v_counter 的值递增至 1,因此 LOOP 再次迭代:

    5981807618.30CCD
  2. 对于 LOOP 的第二次迭代:
    • v_counter = 1
    • v_depart = RDR

    提取以下记录,并且 v_counter 的值递增至 2,因此 LOOP 不会再次迭代,并且 GROUP 前进至下一个记录:

    5981807618.30RDR

GROUP 的第二次迭代:LOOP 的一次迭代

Vendor_Number Invoice_Number 日期 金额 Dept_Code
11663 5981807 2000-11-17 618.30 CCD,RDR
13808 2275301 2000-11-17 6705.12 CCD
12433 6585673 2000-11-17 7955.46 CCD,LMO,RDR

对于该表中的第二个记录,v_department_count 的值是 0,因此 LOOP 迭代一次:

  • v_counter = 0
  • v_depart = CCD

以下记录被提取,并且 v_counter 的值被递增至 1,因此 LOOP 不会再次迭代,GROUP 前进至下一个记录:

2275301 6705.12 CCD

GROUP 的第三次迭代:LOOP 的三次迭代

Vendor_Number Invoice_Number 日期 金额 Dept_Code
11663 5981807 2000-11-17 618.30 CCD,RDR
13808 2275301 2000-11-17 6705.12 CCD
12433 6585673 2000-11-17 7955.46 CCD,LMO,RDR

对于该表中的第三个记录,v_department_count 的值是 2,因此 LOOP 迭代三次:

  1. 对于 LOOP 的第一次迭代:
    • v_counter = 0
    • v_depart = CCD

    提取以下记录,并且 v_counter 的值递增至 1,因此 LOOP 再次迭代:

    65856737955.46CCD
  2. 对于 LOOP 的第二次迭代:
    • v_counter = 1
    • v_depart = LMO

    提取以下记录,并且 v_counter 的值递增至 2,因此 LOOP 再次迭代:

    65856737955.46LMO
  3. 对于 LOOP 的第三次迭代:
    • v_counter = 2
    • v_depart = RDR

    提取以下记录,并且 v_counter 的值递增至 3,因此 LOOP 不会再次迭代,并且 GROUP 到达该表的末尾:

    65856737955.46RDR

最终的结果表

在 GROUP 处理完该表中的每个记录之后,LOOP 已对所有部门代码进行了迭代,您将拥有以下结果表:

Invoice_Number 金额 部门
5981807 618.30 CCD
5981807 618.30 RDR
2275301 6705.12 CCD
6585673 7955.46 CCD
6585673 7955.46 LMO
6585673 7955.46 RDR