Snowflake 存储过程 - 如何更新嵌套 WHILE 和 FOR 循环内声明的“全局变量”

问题描述 投票:0回答:1

在 Snowflake 存储过程中,

  • 我在 DECLARE 块内声明了一个“全局变量”
  • 然后尝试更新 BEGIN 块内嵌套 WHILE 和 FOR 循环中“全局变量”的值
  • 在 BEGIN 块内,我有一个外部 WHILE 循环和一个内部 FOR 循环
  • 我的 WHILE 循环内更新的变量没有传播到下一组 FOR 循环迭代

示例

CREATE OR REPLACE PROCEDURE DBNAME.SCHEMANAME.PROCEDURENAME(
FIELD1 DATE,
FIELD2 DATE
)
RETURNS ARRAY
LANGUAGE SQL
EXECUTE AS CALLER
AS
DECLARE
  COUNTER := 0;
  START_DT DATE;
  END_DT DATE;  
  WORKING_DT DATE;
  WORKING_DT_ARRAY := [];
  WITHIN_FORLOOP_ARRAY := [];
  ELEMENTS_FOR_FORLOOP_ARRAY := [1,2,3,4,5];
BEGIN
  WORKING_DT := $FIELD1;
  START_DT := $FIELD1;
  END_DT := $FIELD2;
  
  WHILE (WORKING_DT <= END_DT) DO
    FOR ELEMENT IN ELEMENTS_FOR_FORLOOP_ARRAY DO
      WITHIN_FORLOOP_ARRAY := ARRAY_APPEND(WITHIN_FORLOOP_ARRAY, WORKING_DT);

    END FOR;

    -- UPDATE WORKING_DT FOR NEXT WHILE LOOP ITERATION
      WORKING_DT_ARRAY := ARRAY_APPEND(WORKING_DT_ARRAY, WORKING_DT);
      WORKING_DT := DATEADD(DAY, 1, WORKING_DT);
      COUNTER := COUNTER+1;

  END WHILE;
  RETURN WITHIN_FORLOOP_ARRAY;
  -- RETURN WORKING_DT_ARRAY;

END;
-- Calling this procedure below returns
-- ['2024-01-01','2024-01-01','2024-01-01','2024-01-01','2024-01-01']
CALL DBNAME.SCHEMANAME.PROCEDURENAME('2024-01-01', '2024-01-02');
-- If I comment out 'RETURN WITHIN_FORLOOP_ARRAY;'
-- and uncomment 'RETURN WORKING_DT_ARRAY;'
-- Calling this procedure below returns
-- ['2024-01-01','2024-01-02']
CALL DBNAME.SCHEMANAME.PROCEDURENAME('2024-01-01', '2024-01-02');

所以问题是,

  1. 为什么 WHILE 循环内“全局变量”WORKING_DT 的更新值没有传递到 FOR 循环中?
  2. 为什么 WHILE 循环只运行 1 组 FOR 循环迭代,而我期望它运行 2 次迭代 - 首先是“2024-01-01”,然后是“2024-01-02”?
loops variables stored-procedures snowflake-cloud-data-platform
1个回答
0
投票

如果我获取代码并将其作为块运行,并对输入进行硬编码:

DECLARE
  COUNTER number := 0;
  START_DT DATE;
  END_DT DATE;  
  WORKING_DT DATE;
  WORKING_DT_ARRAY := [];
  WITHIN_FORLOOP_ARRAY := [];
  ELEMENTS_FOR_FORLOOP_ARRAY := [1,2,3,4,5];
BEGIN
  WORKING_DT := '2024-01-01'::date;
  START_DT := '2024-01-01'::date;
  END_DT := '2024-01-02'::date;
  
  WHILE (WORKING_DT <= END_DT) DO
    FOR ELEMENT IN ELEMENTS_FOR_FORLOOP_ARRAY DO
      WITHIN_FORLOOP_ARRAY := ARRAY_APPEND(WITHIN_FORLOOP_ARRAY, WORKING_DT);

    END FOR;

    -- UPDATE WORKING_DT FOR NEXT WHILE LOOP ITERATION
      WORKING_DT_ARRAY := ARRAY_APPEND(WORKING_DT_ARRAY, WORKING_DT);
      WORKING_DT := DATEADD(DAY, 1, WORKING_DT);
      COUNTER := COUNTER+1;

  END WHILE;
  RETURN WITHIN_FORLOOP_ARRAY;
  --RETURN WORKING_DT_ARRAY;

END;

我得到了你期望的结果:

enter image description here

如果我将它们更改为变量:

set FIELD1 = '2024-01-01'::date;
set FIELD2 = '2024-01-02'::date;

DECLARE
  COUNTER number := 0;
  START_DT DATE;
  END_DT DATE;  
  WORKING_DT DATE;
  WORKING_DT_ARRAY := [];
  WITHIN_FORLOOP_ARRAY := [];
  ELEMENTS_FOR_FORLOOP_ARRAY := [1,2,3,4,5];
BEGIN
  WORKING_DT := $FIELD1;
  START_DT := $FIELD1;
  END_DT := $FIELD2;
  
  WHILE (WORKING_DT <= END_DT) DO
    FOR ELEMENT IN ELEMENTS_FOR_FORLOOP_ARRAY DO
      WITHIN_FORLOOP_ARRAY := ARRAY_APPEND(WITHIN_FORLOOP_ARRAY, WORKING_DT);

    END FOR;

    -- UPDATE WORKING_DT FOR NEXT WHILE LOOP ITERATION
      WORKING_DT_ARRAY := ARRAY_APPEND(WORKING_DT_ARRAY, WORKING_DT);
      WORKING_DT := DATEADD(DAY, 1, WORKING_DT);
      COUNTER := COUNTER+1;

  END WHILE;
  RETURN WITHIN_FORLOOP_ARRAY;
  --RETURN WORKING_DT_ARRAY;

END;

按预期工作...让我们尝试一下该功能:

它也如您所期望的那样工作:

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.