分组和循环

组 和 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 set the initial value of running total to zero END
ASSIGN v_running_total = 0.00

COMMENT iterate over each record in the table and then calculate and extract the running total 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 块内部的命令,并且计算和提取运行合计。如果我们能够在组运行时在其中穿行,则会看到以下过程:

组的第一个迭代:运行合计 = 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

组的第三次迭代:运行合计 = 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 块处理。记录永远不会被组命令中一个以上的 IF/ELSE 块处理。

OPEN Ap_Trans

COMMENT set initial values for running totals END
ASSIGN v_running_total_hi = 0.00
ASSIGN v_running_total_med = 0.00
ASSIGN v_running_total_low = 0.00

COMMENT use GROUP IF to run different ASSIGN and EXTRACT commands depending on invoice amount 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

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

组 内部的 LOOP

使用组处理表中的记录时,您可以一个使用 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
Use GROUP to count commas in each department code field as a way of identifying how many departments are associated with the record
"LOOP" over each record for each code in the field, with each iteration of the loop extracting the record with a single code to the result1 table
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 的 2 次迭代

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 的 1 次迭代

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 的 3 次迭代

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