使用循环

Snowflake Scripting 支持以下类型的循环:

本主题说明如何使用这些类型的循环中的每一种。

FOR 循环

FOR 循环按照指定次数或者为结果集中的每一行重复执行一系列步骤。Snowflake Scripting 支持以下类型的 FOR 循环:

接下来的部分将介绍如何使用这些类型的 FOR 循环。

基于计数器的 FOR 循环

基于计数器的 FOR 循环执行指定的次数。

基于计数器的 FOR 循环的语法为:

FOR <counter_variable> IN [ REVERSE ] <start> TO <end> { DO | LOOP }
  <statement>;
  [ <statement>; ... ]
END { FOR | LOOP } [ <label> ] ;
Copy

例如,以下 FOR 循环执行 5 次:

DECLARE
  counter INTEGER DEFAULT 0;
  maximum_count INTEGER default 5;
BEGIN
  FOR i IN 1 TO maximum_count DO
    counter := counter + 1;
  END FOR;
  RETURN counter;
END;
Copy

注意:如果您在 Python Connector 代码中使用 SnowSQLClassic Console 或者 execute_streamexecute_string 方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):

EXECUTE IMMEDIATE $$
DECLARE
  counter INTEGER DEFAULT 0;
  maximum_count INTEGER default 5;
BEGIN
  FOR i IN 1 TO maximum_count DO
    counter := counter + 1;
  END FOR;
  RETURN counter;
END;
$$
;
Copy
+-----------------+
| anonymous block |
|-----------------|
|               5 |
+-----------------+

有关 FOR 循环的完整语法和详细信息,请参阅 FOR (Snowflake Scripting)

基于游标的 FOR 循环

:doc:` 基于游标 <cursors>` 的 FOR 循环会遍历结果集。迭代次数由 :doc:`游标 <cursors>`中的行数决定。

基于游标的 FOR 循环的语法为:

FOR <row_variable> IN <cursor_name> DO
  <statement>;
  [ <statement>; ... ]
END FOR [ <label> ] ;
Copy

本节中的示例使用了以下 invoices 表中的数据:

CREATE OR REPLACE TABLE invoices (price NUMBER(12, 2));
INSERT INTO invoices (price) VALUES
  (11.11),
  (22.22);
Copy

以下示例使用 FOR 循环来遍历 invoices 表的游标中的行:

DECLARE
  total_price FLOAT;
  c1 CURSOR FOR SELECT price FROM invoices;
BEGIN
  total_price := 0.0;
  FOR record IN c1 DO
    total_price := total_price + record.price;
  END FOR;
  RETURN total_price;
END;
Copy

注意:如果您在 Python Connector 代码中使用 SnowSQLClassic Console 或者 execute_streamexecute_string 方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):

EXECUTE IMMEDIATE $$
DECLARE
  total_price FLOAT;
  c1 CURSOR FOR SELECT price FROM invoices;
BEGIN
  total_price := 0.0;
  FOR record IN c1 DO
    total_price := total_price + record.price;
  END FOR;
  RETURN total_price;
END;
$$
;
Copy
+-----------------+
| anonymous block |
|-----------------|
|           33.33 |
+-----------------+

有关 FOR 循环的完整语法和详细信息,请参阅 FOR (Snowflake Scripting)

基于 RESULTSET 的 FOR 循环

基于 RESULTSET 的 FOR 循环会遍历结果集。迭代次数由 RESULTSET 查询返回的行数决定。

基于 RESULTSET 的 FOR 循环的语法为:

FOR <row_variable> IN <RESULTSET_name> DO
  <statement>;
  [ <statement>; ... ]
END FOR [ <label> ] ;
Copy

本节中的示例使用了以下 invoices 表中的数据:

CREATE OR REPLACE TABLE invoices (price NUMBER(12, 2));
INSERT INTO invoices (price) VALUES
  (11.11),
  (22.22);
Copy

以下代码块使用 FOR 循环遍历 invoices 表的 RESULTSET 中的行:

DECLARE
  total_price FLOAT;
  rs RESULTSET;
BEGIN
  total_price := 0.0;
  rs := (SELECT price FROM invoices);
  FOR record IN rs DO
    total_price := total_price + record.price;
  END FOR;
  RETURN total_price;
END;
Copy

注意:如果您在 Python Connector 代码中使用 SnowSQLClassic Console 或者 execute_streamexecute_string 方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):

EXECUTE IMMEDIATE $$
DECLARE
  total_price FLOAT;
  rs RESULTSET;
BEGIN
  total_price := 0.0;
  rs := (SELECT price FROM invoices);
  FOR record IN rs DO
    total_price := total_price + record.price;
  END FOR;
  RETURN total_price;
END;
$$
;
Copy
+-----------------+
| anonymous block |
|-----------------|
|           33.33 |
+-----------------+

有关 FOR 循环的完整语法和详细信息,请参阅 FOR (Snowflake Scripting)

WHILE 循环

当条件为 true WHILE 循环进行迭代。在 WHILE 循环中,在即将执行循环主体之前检验条件。如果条件在第一次迭代之前为 false,则循环的主体一次都不会执行。

WHILE 循环的语法为:

WHILE ( <condition> ) { DO | LOOP }
  <statement>;
  [ <statement>; ... ]
END { WHILE | LOOP } [ <label> ] ;
Copy

例如:

BEGIN
  LET counter := 0;
  WHILE (counter < 5) DO
    counter := counter + 1;
  END WHILE;
  RETURN counter;
END;
Copy

注意:如果您在 Python Connector 代码中使用 SnowSQLClassic Console 或者 execute_streamexecute_string 方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):

EXECUTE IMMEDIATE $$
BEGIN
  LET counter := 0;
  WHILE (counter < 5) DO
    counter := counter + 1;
  END WHILE;
  RETURN counter;
END;
$$
;
Copy
+-----------------+
| anonymous block |
|-----------------|
|               5 |
+-----------------+

有关 WHILE 循环的完整语法和详细信息,请参阅 WHILE (Snowflake Scripting)

REPEAT 循环

REPEAT 循环一直进行迭代,:emph:` 直至 ` 条件为 true。在 REPEAT 循环中,在执行循环主体之后立即检验条件。因此,循环的主体始终至少执行一次。

REPEAT 循环的语法为:

REPEAT
  <statement>;
  [ <statement>; ... ]
UNTIL ( <condition> )
END REPEAT [ <label> ] ;
Copy

例如:

BEGIN
  LET counter := 5;
  LET number_of_iterations := 0;
  REPEAT
    counter := counter - 1;
    number_of_iterations := number_of_iterations + 1;
  UNTIL (counter = 0)
  END REPEAT;
  RETURN number_of_iterations;
END;
Copy

注意:如果您在 Python Connector 代码中使用 SnowSQLClassic Console 或者 execute_streamexecute_string 方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):

EXECUTE IMMEDIATE $$
BEGIN
  LET counter := 5;
  LET number_of_iterations := 0;
  REPEAT
    counter := counter - 1;
    number_of_iterations := number_of_iterations + 1;
  UNTIL (counter = 0)
  END REPEAT;
  RETURN number_of_iterations;
END;
$$
;
Copy
+-----------------+
| anonymous block |
|-----------------|
|               5 |
+-----------------+

有关 REPEAT 循环的完整语法和详细信息,请参阅 REPEAT (Snowflake Scripting)

LOOP 循环

LOOP 循环一直执行,直到执行 BREAK 命令为止。此类 BREAK 命令通常嵌入在分支逻辑中(例如 IF 语句CASE 语句)。

LOOP 语句的语法为:

LOOP
  <statement>;
  [ <statement>; ... ]
END LOOP [ <label> ] ;
Copy

例如:

BEGIN
  LET counter := 5;
  LOOP
    IF (counter = 0) THEN
      BREAK;
    END IF;
    counter := counter - 1;
  END LOOP;
  RETURN counter;
END;
Copy

注意:如果您在 Python Connector 代码中使用 SnowSQLClassic Console 或者 execute_streamexecute_string 方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):

EXECUTE IMMEDIATE $$
BEGIN
  LET counter := 5;
  LOOP
    IF (counter = 0) THEN
      BREAK;
    END IF;
    counter := counter - 1;
  END LOOP;
  RETURN counter;
END;
$$
;
Copy
+-----------------+
| anonymous block |
|-----------------|
|               0 |
+-----------------+

有关 LOOP 循环的完整语法和详细信息,请参阅 LOOP (Snowflake Scripting)

终止循环或迭代

在循环构造中,可以指定循环或循环的迭代必须在何时提前终止。接下来的部分将对此进行更详细的解释:

终止循环

通过执行 BREAK 命令,可以明确地提前终止循环。BREAK(及其同义词 EXIT)会立即停止当前迭代,并跳过任何剩余的迭代。可以将 BREAK 视为在循环结束后跳转到第一个可执行语句。

BREAK 在 LOOP 循环中是必需的,但在 WHILE、FOR 和 REPEAT 循环中则并非必需。在大多数情况下,如果有要跳过的语句,可以使用标准分支结构( IF 语句CASE 语句 )来控制要执行循环中的哪些语句。

BREAK 命令本身通常位于 IF 或 CASE 语句中。

在不终止循环的情况下终止迭代

可以使用 CONTINUE 或 ITERATE 命令跳转到循环迭代的末尾,以跳过循环中的其余语句。循环在下一次迭代开始时继续。

很少需要进行这种跳转。在大多数情况下,如果有要跳过的语句,可以使用标准分支结构( IF 语句CASE 语句 )来控制要执行循环中的哪些语句。

CONTINUE 或 ITERATE 命令本身通常位于 IF 或 CASE 语句中。

指定终止后应继续执行的位置

在 BREAK 或 CONTINUE 命令中,如果需要在代码中的特定点(例如嵌套循环中的外循环)继续执行,请指定一个标签,用于标识应继续执行的点。

下面的示例在嵌套循环中演示了这一点:

BEGIN
  LET inner_counter := 0;
  LET outer_counter := 0;
  LOOP
    LOOP
      IF (inner_counter < 5) THEN
        inner_counter := inner_counter + 1;
        CONTINUE OUTER;
      ELSE
        BREAK OUTER;
      END IF;
    END LOOP INNER;
    outer_counter := outer_counter + 1;
    BREAK;
  END LOOP OUTER;
  RETURN ARRAY_CONSTRUCT(outer_counter, inner_counter);
END;
Copy

注意:如果您在 Python Connector 代码中使用 SnowSQLClassic Console 或者 execute_streamexecute_string 方法,请改用本示例(请参阅 在 SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting):

EXECUTE IMMEDIATE $$
BEGIN
  LET inner_counter := 0;
  LET outer_counter := 0;
  LOOP
    LOOP
      IF (inner_counter < 5) THEN
        inner_counter := inner_counter + 1;
        CONTINUE OUTER;
      ELSE
        BREAK OUTER;
      END IF;
    END LOOP INNER;
    outer_counter := outer_counter + 1;
    BREAK;
  END LOOP OUTER;
  RETURN ARRAY_CONSTRUCT(outer_counter, inner_counter);
END;
$$;
Copy

在此示例中:

  • 有一个标记为 INNER 的循环,它嵌套在标记为 OUTER 的循环中。

  • CONTINUE OUTER 让带有 OUTER 标签的循环开始另一次迭代。

  • BREAK OUTER 终止内循环,并将控制权转移到外循环(标记为 OUTER)的末尾。

此命令的输出为:

+-----------------+
| anonymous block |
|-----------------|
| [               |
|   0,            |
|   5             |
| ]               |
+-----------------+

如输出所示:

  • inner_counter 最多递增到 5。CONTINUE OUTER 开始新的外循环迭代,新的外循环又会开始新的内循环迭代,内循环将计数器递增到 5。这些迭代一直持续到 inner_counter 的值等于 5,BREAK OUTER 会终止内循环为止。

  • outer_counter 从不递增。由于 BREAK OUTER 将控制权转移到外循环的末尾,因此从不会到达让此计数器递增的语句。

语言: 中文