Este tópico explica como usar cada um desses tipos de loops.
Loop FOR
Um loop FOR repete uma sequência de passos por um número especificado de vezes ou para cada linha em um conjunto de resultados. O Script Snowflake oferece suporte para os seguintes tipos de loops FOR:
As próximas seções explicam como utilizar esses tipos de loops FOR.
Loops FOR baseados em contador
Um loop FOR baseado em contador é executado um número especificado de vezes.
Use a seguinte sintaxe para um loop FOR baseado em contador:
FOR <counter_variable> IN [ REVERSE ] <start> TO <end> { DO | LOOP }
<statement>;
[ <statement>; ... ]
END { FOR | LOOP } [ <label> ] ;
Por exemplo, o seguinte loop FOR é executado cinco vezes:
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;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
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;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 5 |
+-----------------+
Você pode incluir instruções SQL dentro dos loops do Snowflake Scripting. Por exemplo, o seguinte loop FOR executa uma instrução INSERT cinco vezes para inserir o valor do contador em uma tabela:
DECLARE
counter INTEGER DEFAULT 0;
maximum_count INTEGER default 5;
BEGIN
CREATE OR REPLACE TABLE test_for_loop_insert(i INTEGER);
FOR i IN 1 TO maximum_count DO
INSERT INTO test_for_loop_insert VALUES (:i);
counter := counter + 1;
END FOR;
RETURN counter || ' rows inserted';
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
counter INTEGER DEFAULT 0;
maximum_count INTEGER default 5;
BEGIN
CREATE OR REPLACE TABLE test_for_loop_insert(i INTEGER);
FOR i IN 1 TO maximum_count DO
INSERT INTO test_for_loop_insert VALUES (:i);
counter := counter + 1;
END FOR;
RETURN counter || ' rows inserted';
END;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 5 rows inserted |
+-----------------+
Consultar a tabela para visualizar as linhas inseridas:
SELECT * FROM test_for_loop_insert;
+---+
| I |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+---+
O exemplo a seguir usa um loop FOR baseado em contador para preencher uma tabela de dimensão de data, o que é uma tarefa comum na criação de um data warehouse. O loop itera com base em um intervalo de dias e insere uma linha para cada data com atributos computados:
DECLARE
start_date DATE DEFAULT '2025-01-01';
current_date_val DATE;
BEGIN
CREATE OR REPLACE TABLE date_dimension (
date_key INTEGER,
full_date DATE,
day_of_week VARCHAR,
month_name VARCHAR,
quarter INTEGER,
year INTEGER
);
FOR i IN 1 TO 7 DO
current_date_val := DATEADD('day', :i - 1, :start_date);
INSERT INTO date_dimension
SELECT :i, :current_date_val, DAYNAME(:current_date_val),
MONTHNAME(:current_date_val), QUARTER(:current_date_val),
YEAR(:current_date_val);
END FOR;
RETURN 'Populated date dimension with 7 rows';
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
start_date DATE DEFAULT '2025-01-01';
current_date_val DATE;
BEGIN
CREATE OR REPLACE TABLE date_dimension (
date_key INTEGER,
full_date DATE,
day_of_week VARCHAR,
month_name VARCHAR,
quarter INTEGER,
year INTEGER
);
FOR i IN 1 TO 7 DO
current_date_val := DATEADD('day', :i - 1, :start_date);
INSERT INTO date_dimension
SELECT :i, :current_date_val, DAYNAME(:current_date_val),
MONTHNAME(:current_date_val), QUARTER(:current_date_val),
YEAR(:current_date_val);
END FOR;
RETURN 'Populated date dimension with 7 rows';
END;
$$
;
+----------------------------------------+
| anonymous block |
|----------------------------------------|
| Populated date dimension with 7 rows |
+----------------------------------------+
Para verificar os resultados, consulte a tabela:
SELECT * FROM date_dimension ORDER BY date_key;
+----------+------------+-------------+------------+---------+------+
| DATE_KEY | FULL_DATE | DAY_OF_WEEK | MONTH_NAME | QUARTER | YEAR |
|----------+------------+-------------+------------+---------+------|
| 1 | 2025-01-01 | Wed | Jan | 1 | 2025 |
| 2 | 2025-01-02 | Thu | Jan | 1 | 2025 |
| 3 | 2025-01-03 | Fri | Jan | 1 | 2025 |
| 4 | 2025-01-04 | Sat | Jan | 1 | 2025 |
| 5 | 2025-01-05 | Sun | Jan | 1 | 2025 |
| 6 | 2025-01-06 | Mon | Jan | 1 | 2025 |
| 7 | 2025-01-07 | Tue | Jan | 1 | 2025 |
+----------+------------+-------------+------------+---------+------+
Para obter a sintaxe completa e detalhes sobre loops FOR, consulte FOR (Script Snowflake).
Loops FOR baseados em cursor
Um loop FOR baseado em cursor itera com base em um conjunto de resultados. O número de iterações é determinado pelo número de linhas no cursor.
A sintaxe para um loop FOR baseado em cursor é:
FOR <row_variable> IN <cursor_name> DO
<statement>;
[ <statement>; ... ]
END FOR [ <label> ] ;
O primeiro exemplo desta seção usa os dados da seguinte tabela invoices:
CREATE OR REPLACE TABLE invoices (price NUMBER(12, 2));
INSERT INTO invoices (price) VALUES
(11.11),
(22.22);
O seguinte exemplo usa um loop FOR para iterar sobre as linhas em um cursor na tabela 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;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
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;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 33.33 |
+-----------------+
O seguinte exemplo usa um loop FOR baseado em cursor para iterar sobre uma tabela de funcionários, dar a cada funcionário um aumento com base em seu departamento e inserir um registro de auditoria para cada atualização:
CREATE OR REPLACE TABLE loop_test_employees (
emp_id INTEGER,
name VARCHAR,
department VARCHAR,
salary NUMBER(12,2));
INSERT INTO loop_test_employees VALUES
(1, 'Alice', 'Engineering', 90000),
(2, 'Bob', 'Sales', 70000),
(3, 'Carol', 'Engineering', 95000),
(4, 'Dave', 'Sales', 72000);
CREATE OR REPLACE TABLE salary_audit (
emp_id INTEGER,
old_salary NUMBER(12,2),
new_salary NUMBER(12,2),
updated_on TIMESTAMP);
DECLARE
rows_updated INTEGER DEFAULT 0;
raise_pct INTEGER;
new_salary NUMBER(12,2);
cur_emp_id INTEGER;
cur_salary NUMBER(12,2);
c1 CURSOR FOR SELECT emp_id, department, salary FROM loop_test_employees;
BEGIN
FOR record IN c1 DO
cur_emp_id := record.emp_id;
cur_salary := record.salary;
IF (record.department = 'Engineering') THEN
raise_pct := 10;
ELSE
raise_pct := 5;
END IF;
new_salary := :cur_salary * (1 + :raise_pct / 100);
UPDATE loop_test_employees SET salary = :new_salary WHERE emp_id = :cur_emp_id;
INSERT INTO salary_audit
SELECT :cur_emp_id, :cur_salary, :new_salary, CURRENT_TIMESTAMP();
rows_updated := rows_updated + 1;
END FOR;
RETURN rows_updated || ' employees updated';
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
rows_updated INTEGER DEFAULT 0;
raise_pct INTEGER;
new_salary NUMBER(12,2);
cur_emp_id INTEGER;
cur_salary NUMBER(12,2);
c1 CURSOR FOR SELECT emp_id, department, salary FROM loop_test_employees;
BEGIN
FOR record IN c1 DO
cur_emp_id := record.emp_id;
cur_salary := record.salary;
IF (record.department = 'Engineering') THEN
raise_pct := 10;
ELSE
raise_pct := 5;
END IF;
new_salary := :cur_salary * (1 + :raise_pct / 100);
UPDATE loop_test_employees SET salary = :new_salary WHERE emp_id = :cur_emp_id;
INSERT INTO salary_audit
SELECT :cur_emp_id, :cur_salary, :new_salary, CURRENT_TIMESTAMP();
rows_updated := rows_updated + 1;
END FOR;
RETURN rows_updated || ' employees updated';
END;
$$
;
+----------------------+
| anonymous block |
|----------------------|
| 4 employees updated |
+----------------------+
Para verificar as atualizações, consulte as tabelas:
SELECT emp_id, name, department, salary FROM loop_test_employees ORDER BY emp_id;
+--------+-------+-------------+-----------+
| EMP_ID | NAME | DEPARTMENT | SALARY |
|--------+-------+-------------+-----------|
| 1 | Alice | Engineering | 99000.00 |
| 2 | Bob | Sales | 73500.00 |
| 3 | Carol | Engineering | 104500.00 |
| 4 | Dave | Sales | 75600.00 |
+--------+-------+-------------+-----------+
SELECT emp_id, old_salary, new_salary FROM salary_audit ORDER BY emp_id;
+--------+------------+------------+
| EMP_ID | OLD_SALARY | NEW_SALARY |
|--------+------------+------------|
| 1 | 90000.00 | 99000.00 |
| 2 | 70000.00 | 73500.00 |
| 3 | 95000.00 | 104500.00 |
| 4 | 72000.00 | 75600.00 |
+--------+------------+------------+
Para obter a sintaxe completa e detalhes sobre loops FOR, consulte FOR (Script Snowflake).
Loops FOR baseados em RESULTSET
O loop FOR baseado em RESULTSET itera com base em um conjunto de resultados. O número de iterações é determinado pelo número de linhas retornadas pela consulta RESULTSET.
A sintaxe de um loop FOR baseado em RESULTSET é:
FOR <row_variable> IN <RESULTSET_name> DO
<statement>;
[ <statement>; ... ]
END FOR [ <label> ] ;
O primeiro exemplo desta seção usa os dados da seguinte tabela invoices:
CREATE OR REPLACE TABLE invoices (price NUMBER(12, 2));
INSERT INTO invoices (price) VALUES
(11.11),
(22.22);
O seguinte exemplo usa um loop FOR para iterar com base nas linhas em um RESULTSET da tabela invoices:
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;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
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;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 33.33 |
+-----------------+
O seguinte exemplo usa um loop FOR baseado em RESULTSET para validar registros de clientes. Ele verifica as informações de contato necessárias em cada registro e atualiza a coluna status para marcar cada registro como verificado ou incompleto. Esse tipo de verificação de qualidade de dados é uma etapa comum nos pipelines de extração, transformação e carregamento (Extract, Transform, and Load, ETL):
CREATE OR REPLACE TABLE loop_test_customers (
customer_id INTEGER,
customer_name VARCHAR,
customer_email VARCHAR,
customer_phone VARCHAR,
status VARCHAR DEFAULT 'pending_review');
INSERT INTO loop_test_customers (customer_id, customer_name, customer_email, customer_phone) VALUES
(1, 'Alice Smith', 'alice@example.com', '800-555-0101'),
(2, 'Bob Jones', NULL, '800-555-0102'),
(3, 'Carol White', 'carol@example.com', NULL),
(4, 'Dave Brown', NULL, NULL),
(5, 'Eve Davis', 'eve@example.com', '800-555-0105');
DECLARE
rs RESULTSET;
valid_count INTEGER DEFAULT 0;
invalid_count INTEGER DEFAULT 0;
cur_customer_id INTEGER;
BEGIN
rs := (SELECT customer_id, customer_email, customer_phone FROM loop_test_customers WHERE status = 'pending_review');
FOR record IN rs DO
cur_customer_id := record.customer_id;
IF (record.customer_email IS NOT NULL AND record.customer_phone IS NOT NULL) THEN
UPDATE loop_test_customers SET status = 'verified' WHERE customer_id = :cur_customer_id;
valid_count := valid_count + 1;
ELSE
UPDATE loop_test_customers SET status = 'incomplete' WHERE customer_id = :cur_customer_id;
invalid_count := invalid_count + 1;
END IF;
END FOR;
RETURN 'Verified: ' || valid_count || ', Incomplete: ' || invalid_count;
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
rs RESULTSET;
valid_count INTEGER DEFAULT 0;
invalid_count INTEGER DEFAULT 0;
cur_customer_id INTEGER;
BEGIN
rs := (SELECT customer_id, customer_email, customer_phone FROM loop_test_customers WHERE status = 'pending_review');
FOR record IN rs DO
cur_customer_id := record.customer_id;
IF (record.customer_email IS NOT NULL AND record.customer_phone IS NOT NULL) THEN
UPDATE loop_test_customers SET status = 'verified' WHERE customer_id = :cur_customer_id;
valid_count := valid_count + 1;
ELSE
UPDATE loop_test_customers SET status = 'incomplete' WHERE customer_id = :cur_customer_id;
invalid_count := invalid_count + 1;
END IF;
END FOR;
RETURN 'Verified: ' || valid_count || ', Incomplete: ' || invalid_count;
END;
$$
;
+-------------------------------+
| anonymous block |
|-------------------------------|
| Verified: 2, Incomplete: 3 |
+-------------------------------+
Para verificar as alterações, consulte a tabela:
SELECT * FROM loop_test_customers ORDER BY customer_id;
+-------------+-----------------+-------------------+----------------+------------+
| CUSTOMER_ID | CUSTOMER_NAME | CUSTOMER_EMAIL | CUSTOMER_PHONE | STATUS |
|-------------+-----------------+-------------------+----------------+------------|
| 1 | Alice Smith | alice@example.com | 800-555-0101 | verified |
| 2 | Bob Jones | NULL | 800-555-0102 | incomplete |
| 3 | Carol White | carol@example.com | NULL | incomplete |
| 4 | Dave Brown | NULL | NULL | incomplete |
| 5 | Eve Davis | eve@example.com | 800-555-0105 | verified |
+-------------+-----------------+-------------------+----------------+------------+
Para obter a sintaxe completa e detalhes sobre loops FOR, consulte FOR (Script Snowflake).
Loop WHILE
Um loop WHILE itera enquanto a condição for verdadeira. Em um loop WHILE, a condição é testada imediatamente antes de executar o corpo do loop. Se a condição for falsa antes da primeira iteração, o corpo do loop não é executado nem mesmo uma vez.
A sintaxe de um loop WHILE é:
WHILE ( <condition> ) { DO | LOOP }
<statement>;
[ <statement>; ... ]
END { WHILE | LOOP } [ <label> ] ;
Por exemplo:
BEGIN
LET counter := 0;
WHILE (counter < 5) DO
counter := counter + 1;
END WHILE;
RETURN counter;
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
BEGIN
LET counter := 0;
WHILE (counter < 5) DO
counter := counter + 1;
END WHILE;
RETURN counter;
END;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 5 |
+-----------------+
O exemplo a seguir usa um loop WHILE para criar um resumo de vendas diário com base nos dados brutos das transações. Ele processa uma data de cada vez, agregando as transações para essa data em uma linha de resumo e marcando-as como carregadas. Esse padrão de resumo por data é comum nos pipelines de extração, transformação e carregamento (ETL):
CREATE OR REPLACE TABLE loop_test_raw_transactions (
txn_id INTEGER,
amount NUMBER(12,2),
txn_date DATE,
loaded BOOLEAN DEFAULT FALSE);
INSERT INTO loop_test_raw_transactions (txn_id, amount, txn_date) VALUES
(1, 150.00, '2025-03-01'),
(2, 230.50, '2025-03-01'),
(3, 89.99, '2025-03-01'),
(4, 412.00, '2025-03-02'),
(5, 55.25, '2025-03-03'),
(6, 178.75, '2025-03-03');
CREATE OR REPLACE TABLE loop_test_daily_sales_summary (
summary_date DATE,
total_sales NUMBER(12,2),
txn_count INTEGER);
DECLARE
next_date DATE;
BEGIN
next_date := (SELECT MIN(txn_date) FROM loop_test_raw_transactions WHERE NOT loaded);
WHILE (next_date IS NOT NULL) DO
INSERT INTO loop_test_daily_sales_summary
SELECT txn_date, SUM(amount), COUNT(*)
FROM loop_test_raw_transactions
WHERE txn_date = :next_date AND NOT loaded
GROUP BY txn_date;
UPDATE loop_test_raw_transactions SET loaded = TRUE WHERE txn_date = :next_date;
next_date := (SELECT MIN(txn_date) FROM loop_test_raw_transactions WHERE NOT loaded);
END WHILE;
RETURN 'Daily summaries created for all transaction dates';
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
next_date DATE;
BEGIN
next_date := (SELECT MIN(txn_date) FROM loop_test_raw_transactions WHERE NOT loaded);
WHILE (next_date IS NOT NULL) DO
INSERT INTO loop_test_daily_sales_summary
SELECT txn_date, SUM(amount), COUNT(*)
FROM loop_test_raw_transactions
WHERE txn_date = :next_date AND NOT loaded
GROUP BY txn_date;
UPDATE loop_test_raw_transactions SET loaded = TRUE WHERE txn_date = :next_date;
next_date := (SELECT MIN(txn_date) FROM loop_test_raw_transactions WHERE NOT loaded);
END WHILE;
RETURN 'Daily summaries created for all transaction dates';
END;
$$
;
+----------------------------------------------------+
| anonymous block |
|----------------------------------------------------|
| Daily summaries created for all transaction dates |
+----------------------------------------------------+
Para verificar os resultados, consulte a tabela de resumo:
SELECT * FROM loop_test_daily_sales_summary ORDER BY summary_date;
+--------------+-------------+-----------+
| SUMMARY_DATE | TOTAL_SALES | TXN_COUNT |
|--------------+-------------+-----------|
| 2025-03-01 | 470.49 | 3 |
| 2025-03-02 | 412.00 | 1 |
| 2025-03-03 | 234.00 | 2 |
+--------------+-------------+-----------+
Para obter a sintaxe completa e detalhes sobre loops WHILE, consulte WHILE (Script Snowflake).
Loop REPEAT
Um loop REPEAT itera até uma condição ser verdadeira. Em um loop REPEAT, a condição é testada imediatamente após a execução do corpo do loop. Como resultado, o corpo do loop sempre é executado pelo menos uma vez.
A sintaxe de um loop REPEAT é:
REPEAT
<statement>;
[ <statement>; ... ]
UNTIL ( <condition> )
END REPEAT [ <label> ] ;
Por exemplo:
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;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
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;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 5 |
+-----------------+
O exemplo a seguir cria uma tabela de preparação e uma tabela de destino com uma coluna batch_id adicional. Em seguida, ele usa um loop REPEAT para mover as linhas em lotes da tabela de preparação para a tabela de destino, incrementando o ID do lote após cada iteração, até que não haja mais linhas na tabela de preparação:
CREATE OR REPLACE TABLE loop_test_orders_staging (
order_id INTEGER,
customer VARCHAR,
amount NUMBER(12,2));
INSERT INTO loop_test_orders_staging VALUES
(101, 'TestA Corp', 500.00),
(102, 'TestB Corp', 1200.00),
(103, 'TestA Corp', 300.00),
(104, 'TestC Corp', 750.00),
(105, 'TestB Corp', 425.00),
(106, 'TestC Corp', 980.00);
CREATE OR REPLACE TABLE loop_test_orders_processed (
order_id INTEGER,
customer VARCHAR,
amount NUMBER(12,2),
batch_id INTEGER);
DECLARE
batch_size INTEGER DEFAULT 2;
batch_id INTEGER DEFAULT 1;
remaining INTEGER;
BEGIN
remaining := (SELECT COUNT(*) FROM loop_test_orders_staging);
REPEAT
INSERT INTO loop_test_orders_processed
SELECT order_id, customer, amount, :batch_id
FROM loop_test_orders_staging
ORDER BY order_id
LIMIT :batch_size;
DELETE FROM loop_test_orders_staging WHERE order_id IN (
SELECT order_id
FROM loop_test_orders_processed
WHERE batch_id = :batch_id
);
batch_id := batch_id + 1;
remaining := (SELECT COUNT(*) FROM loop_test_orders_staging);
UNTIL (remaining = 0)
END REPEAT;
RETURN 'Processed all orders in ' || (batch_id - 1) || ' batches';
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
batch_size INTEGER DEFAULT 2;
batch_id INTEGER DEFAULT 1;
remaining INTEGER;
BEGIN
remaining := (SELECT COUNT(*) FROM loop_test_orders_staging);
REPEAT
INSERT INTO loop_test_orders_processed
SELECT order_id, customer, amount, :batch_id
FROM loop_test_orders_staging
ORDER BY order_id
LIMIT :batch_size;
DELETE FROM loop_test_orders_staging WHERE order_id IN (
SELECT order_id
FROM loop_test_orders_processed
WHERE batch_id = :batch_id
);
batch_id := batch_id + 1;
remaining := (SELECT COUNT(*) FROM loop_test_orders_staging);
UNTIL (remaining = 0)
END REPEAT;
RETURN 'Processed all orders in ' || (batch_id - 1) || ' batches';
END;
$$
;
+------------------------------------+
| anonymous block |
|------------------------------------|
| Processed all orders in 3 batches |
+------------------------------------+
Para verificar os resultados, consulte a tabela de destino:
SELECT * FROM loop_test_orders_processed ORDER BY batch_id, order_id;
+----------+------------+---------+----------+
| ORDER_ID | CUSTOMER | AMOUNT | BATCH_ID |
|----------+------------+---------+----------|
| 101 | TestA Corp | 500.00 | 1 |
| 102 | TestB Corp | 1200.00 | 1 |
| 103 | TestA Corp | 300.00 | 2 |
| 104 | TestC Corp | 750.00 | 2 |
| 105 | TestB Corp | 425.00 | 3 |
| 106 | TestC Corp | 980.00 | 3 |
+----------+------------+---------+----------+
Para obter a sintaxe completa e detalhes sobre loops REPEAT, consulte REPEAT (Script Snowflake).
Loop LOOP
Um loop LOOP é executado até que um comando BREAK seja executado. Um comando BREAK normalmente é incorporado dentro da lógica de ramificação (por exemplo, Instruções IF ou Instruções CASE).
A sintaxe para uma instrução LOOP é:
LOOP
<statement>;
[ <statement>; ... ]
END LOOP [ <label> ] ;
Por exemplo:
BEGIN
LET counter := 5;
LOOP
IF (counter = 0) THEN
BREAK;
END IF;
counter := counter - 1;
END LOOP;
RETURN counter;
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
BEGIN
LET counter := 5;
LOOP
IF (counter = 0) THEN
BREAK;
END IF;
counter := counter - 1;
END LOOP;
RETURN counter;
END;
$$
;
+-----------------+
| anonymous block |
|-----------------|
| 0 |
+-----------------+
O exemplo a seguir cria uma tabela de log com entradas que abrangem várias datas. Ele usa um LOOP para arquivar as linhas mais antigas que uma data limite em uma tabela de arquivamento e excluí-las da fonte, processando um dia de cada vez até que não haja linhas qualificadas:
CREATE OR REPLACE TABLE loop_test_event_log (
event_id INTEGER,
event_date DATE,
event_description VARCHAR);
INSERT INTO loop_test_event_log VALUES
(1, DATEADD('month', -3, CURRENT_DATE()), 'User login'),
(2, DATEADD('month', -3, CURRENT_DATE()), 'File upload'),
(3, DATEADD('month', -2, CURRENT_DATE()), 'Password change'),
(4, DATEADD('month', -1, CURRENT_DATE()), 'User login'),
(5, DATEADD('month', -1, CURRENT_DATE()), 'Data export');
CREATE OR REPLACE TABLE loop_test_event_log_archive (
event_id INTEGER,
event_date DATE,
event_description VARCHAR,
archived_on DATE);
DECLARE
cutoff_date DATE DEFAULT DATEADD('month', -1, CURRENT_DATE());
oldest_date DATE;
archived_total INTEGER DEFAULT 0;
batch_count INTEGER;
BEGIN
LOOP
oldest_date := (SELECT MIN(event_date)
FROM loop_test_event_log
WHERE event_date < :cutoff_date);
IF (oldest_date IS NULL) THEN
BREAK;
END IF;
batch_count := (SELECT COUNT(*)
FROM loop_test_event_log
WHERE event_date = :oldest_date);
INSERT INTO loop_test_event_log_archive
SELECT event_id, event_date, event_description, CURRENT_DATE()
FROM loop_test_event_log
WHERE event_date = :oldest_date;
DELETE FROM loop_test_event_log WHERE event_date = :oldest_date;
archived_total := archived_total + batch_count;
END LOOP;
RETURN 'Archived ' || archived_total || ' events';
END;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
EXECUTE IMMEDIATE $$
DECLARE
cutoff_date DATE DEFAULT DATEADD('month', -1, CURRENT_DATE());
oldest_date DATE;
archived_total INTEGER DEFAULT 0;
batch_count INTEGER;
BEGIN
LOOP
oldest_date := (SELECT MIN(event_date)
FROM loop_test_event_log
WHERE event_date < :cutoff_date);
IF (oldest_date IS NULL) THEN
BREAK;
END IF;
batch_count := (SELECT COUNT(*)
FROM loop_test_event_log
WHERE event_date = :oldest_date);
INSERT INTO loop_test_event_log_archive
SELECT event_id, event_date, event_description, CURRENT_DATE()
FROM loop_test_event_log
WHERE event_date = :oldest_date;
DELETE FROM loop_test_event_log WHERE event_date = :oldest_date;
archived_total := archived_total + batch_count;
END LOOP;
RETURN 'Archived ' || archived_total || ' events';
END;
$$
;
+---------------------+
| anonymous block |
|---------------------|
| Archived 3 events |
+---------------------+
Para verificar os resultados, consulte ambas as tabelas:
SELECT * FROM loop_test_event_log ORDER BY event_id;
+----------+------------+-------------------+
| EVENT_ID | EVENT_DATE | EVENT_DESCRIPTION |
|----------+------------+-------------------|
| 4 | 2026-02-04 | User login |
| 5 | 2026-02-04 | Data export |
+----------+------------+-------------------+
SELECT event_id,
event_date,
event_description
FROM loop_test_event_log_archive
ORDER BY event_id;
+----------+------------+-------------------+
| EVENT_ID | EVENT_DATE | EVENT_DESCRIPTION |
|----------+------------+-------------------|
| 1 | 2025-12-04 | User login |
| 2 | 2025-12-04 | File upload |
| 3 | 2026-01-04 | Password change |
+----------+------------+-------------------+
Para obter a sintaxe completa e detalhes sobre loops LOOP, consulte LOOP (Script Snowflake).
Encerramento de um loop ou iteração
Em uma construção de loop, você pode especificar quando o loop ou uma iteração do loop deve terminar mais cedo. As próximas seções explicam isso com mais detalhes:
Encerramento de um loop
Você pode encerrar explicitamente um loop antecipadamente executando o comando BREAK. BREAK (e seu sinônimo EXIT) interrompe imediatamente a iteração atual e ignora quaisquer iterações restantes. Você pode pensar em BREAK como um salto para a primeira instrução executável após o final do loop.
BREAK é necessário em um loop LOOP, mas não é necessário em loops WHILE, FOR e REPEAT. Na maioria dos casos, se você tem instruções que deseja pular, você pode usar as construções de ramificação padrão (Instruções IF e Instruções CASE) para controlar quais instruções dentro de um loop serão executadas.
Um comando BREAK em si normalmente está dentro de uma instrução IF ou CASE.
Como encerrar uma iteração sem encerrar o loop
Você pode usar o comando CONTINUE (ou ITERATE) para pular para o final de uma iteração de um loop, pulando as instruções restantes no loop. O loop continua no início da próxima iteração.
Tais saltos raramente são necessários. Na maioria dos casos, se você tem instruções que deseja pular, você pode usar as construções de ramificação padrão (Instruções IF e Instruções CASE) para controlar quais instruções dentro de um loop serão executadas.
Um comando CONTINUE ou ITERATE normalmente está dentro de uma instrução IF ou CASE.
Como especificar onde a execução deve continuar após o término
Em um comando BREAK ou CONTINUE, se você precisar continuar a execução em um ponto específico do código (por exemplo, o loop externo em um loop aninhado), especifique uma etiqueta que identifique o ponto em que a execução deve continuar.
O exemplo a seguir demonstra isso em um loop aninhado:
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;
Observação: se você usa a Snowflake CLI, o SnowSQL, o Console clássico, o método execute_stream ou execute_string no código do conector Python, use este exemplo (consulte Using Snowflake Scripting in Snowflake CLI, SnowSQL, and Python Connector):
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;
$$;
Neste exemplo:
Há um loop com a etiqueta INNER que está aninhado em um loop com a etiqueta OUTER.
CONTINUE OUTER inicia outra iteração do loop com a etiqueta OUTER.
BREAK OUTER encerra o loop interno e transfere o controle para o final do loop externo (com a etiqueta OUTER).
A saída desse comando é:
+-----------------+
| anonymous block |
|-----------------|
| [ |
| 0, |
| 5 |
| ] |
+-----------------+
Como mostrado na saída:
inner_counter é incrementado até 5. CONTINUE OUTER inicia uma nova iteração do loop externo, que inicia uma nova iteração do loop interno, que incrementa esse contador até 5. Essas iterações continuam até que o valor de inner_counter seja igual a 5 e BREAK OUTER termina o loop interno.
outer_counter nunca é incrementado. A instrução que aumenta esse contador nunca é alcançada porque BREAK OUTER transfere o controle para o final do loop externo.