Cette rubrique explique comment utiliser chacun de ces types de boucles.
boucle FOR
Une boucle FOR répète une séquence d’étapes pour un nombre spécifié de fois ou pour chaque ligne d’un jeu de résultats. Exécution de scripts Snowflake prend en charge les types suivants de boucles FOR :
Les sections suivantes expliquent comment utiliser ces types de boucles FOR.
Boucles FOR basées sur le compteur
Une boucle FOR basée sur un compteur s’exécute un nombre déterminé de fois.
Utilisez la syntaxe suivante pour une boucle FOR basée sur un compteur :
FOR <counter_variable> IN [ REVERSE ] <start> TO <end> { DO | LOOP }
<statement>;
[ <statement>; ... ]
END { FOR | LOOP } [ <label> ] ;
Par exemple, la boucle FOR suivante s’exécute cinq fois :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-----------------+
Vous pouvez inclure des instructions SQL dans les boucles Snowflake Scripting. Par exemple, la boucle FOR suivante exécute cinq fois une instruction INSERT pour insérer la valeur du compteur dans une table :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-----------------+
Interrogez la table pour afficher les lignes insérées :
SELECT * FROM test_for_loop_insert;
+---+
| I |
|---|
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+---+
L’exemple suivant utilise une boucle FOR basée sur un compteur pour alimenter une table de dimension de date, ce qui est une tâche courante lors de la configuration d’un entrepôt de données. La boucle itère sur une plage de jours et insère une ligne pour chaque date avec des attributs calculés :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+----------------------------------------+
Pour vérifier les résultats, interrogez la table :
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 |
+----------+------------+-------------+------------+---------+------+
Pour une syntaxe complète et des détails sur les boucles FOR, voir FOR (Exécution de scripts Snowflake).
Boucles FOR basées sur le curseur
Une boucle FOR basée sur un curseur itère sur un jeu de résultats. Le nombre d’itérations est déterminé par le nombre de lignes dans le curseur.
La syntaxe d’une boucle FOR basée sur le curseur est la suivante :
FOR <row_variable> IN <cursor_name> DO
<statement>;
[ <statement>; ... ]
END FOR [ <label> ] ;
Le premier exemple de cette section utilise les données de la table invoices suivante :
CREATE OR REPLACE TABLE invoices (price NUMBER(12, 2));
INSERT INTO invoices (price) VALUES
(11.11),
(22.22);
L’exemple suivant utilise une boucle FOR pour itérer sur les lignes d’un curseur pour la table 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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-----------------+
L’exemple suivant utilise une boucle FOR basée sur un curseur pour effectuer une itération sur une table d’employés, donner à chaque employé une augmentation en fonction de son département, et insérer un enregistrement d’audit pour chaque mise à jour :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+----------------------+
Pour vérifier les mises à jour, interrogez les tables :
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 |
+--------+------------+------------+
Pour une syntaxe complète et des détails sur les boucles FOR, voir FOR (Exécution de scripts Snowflake).
Boucles FOR basées sur RESULTSET
Une boucle FOR basée sur un RESULTSET itère sur un jeu de résultats. Le nombre d’itérations est déterminé par le nombre de lignes renvoyées par la requête RESULTSET.
La syntaxe d’une boucle FOR basée sur RESULTSET est la suivante :
FOR <row_variable> IN <RESULTSET_name> DO
<statement>;
[ <statement>; ... ]
END FOR [ <label> ] ;
Le premier exemple de cette section utilise les données de la table invoices suivante :
CREATE OR REPLACE TABLE invoices (price NUMBER(12, 2));
INSERT INTO invoices (price) VALUES
(11.11),
(22.22);
L’exemple suivant utilise une boucle FOR pour itérer sur les lignes d’un RESULTSET pour la table 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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-----------------+
L’exemple suivant utilise une boucle FOR basée sur un RESULTSET pour valider les enregistrements des clients. Elle vérifie chaque enregistrement pour connaître les informations de contact requises et met à jour la colonne status pour marquer chaque enregistrement comme vérifié ou incomplet. Ce type de contrôle de qualité des données est une étape courante lors de l’extraction, de la transformation et du chargement (ETL) des pipelines :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-------------------------------+
Pour vérifier les modifications, interrogez la table :
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 |
+-------------+-----------------+-------------------+----------------+------------+
Pour une syntaxe complète et des détails sur les boucles FOR, voir FOR (Exécution de scripts Snowflake).
boucle WHILE
Une boucle WHILE itère pendant qu’une condition est vraie. Dans une boucle WHILE, la condition est testée immédiatement avant l’exécution du corps de la boucle. Si la condition est fausse avant la première itération, le corps de la boucle ne s’exécute pas une seule fois.
La syntaxe d’une boucle WHILE est la suivante :
WHILE ( <condition> ) { DO | LOOP }
<statement>;
[ <statement>; ... ]
END { WHILE | LOOP } [ <label> ] ;
Par exemple :
BEGIN
LET counter := 0;
WHILE (counter < 5) DO
counter := counter + 1;
END WHILE;
RETURN counter;
END;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-----------------+
L’exemple suivant utilise une boucle WHILE pour créer un résumé quotidien des ventes à partir des données brutes des transactions. Elle traite une date à la fois, en regroupant les transactions de cette date dans une ligne de résumé et en les marquant comme chargées. Ce modèle de résumé date par date est courant dans l’extraction, la transformation et le chargement (ETL) des pipelines :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+----------------------------------------------------+
Pour vérifier les résultats, interrogez la table récapitulative :
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 |
+--------------+-------------+-----------+
Pour une syntaxe complète et des détails sur les boucles WHILE, voir WHILE (Exécution de scripts Snowflake).
boucle REPEAT
Une boucle REPEAT itère jusqu’à ce qu’une condition soit vraie. Dans une boucle REPEAT, la condition est testée immédiatement après l’exécution du corps de la boucle. Par conséquent, le corps de la boucle s’exécute toujours au moins une fois.
La syntaxe d’une boucle REPEAT est la suivante :
REPEAT
<statement>;
[ <statement>; ... ]
UNTIL ( <condition> )
END REPEAT [ <label> ] ;
Par exemple :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-----------------+
L’exemple suivant crée une table mise en zone de préparation et une table cible avec une colonne batch_id supplémentaire. Elle utilise ensuite une boucle REPEAT pour déplacer des lignes par lots de la table de mise en zone de préparation vers la table cible, en incrémentant l’ID des lots après chaque itération, jusqu’à ce qu’il ne reste aucune ligne dans la table mise en zone de préparation :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+------------------------------------+
Pour vérifier les résultats, interrogez la table cible :
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 |
+----------+------------+---------+----------+
Pour une syntaxe complète et des détails sur les boucles REPEAT, voir REPEAT (Exécution de scripts Snowflake).
boucle LOOP
Une boucle LOOP s’exécute jusqu’à ce qu’une commande BREAK soit exécutée. Une commande BREAK est normalement intégrée dans une logique « branching » (par exemple, Instructions IF ou Instructions CASE).
La syntaxe d’une instruction LOOP est la suivante :
LOOP
<statement>;
[ <statement>; ... ]
END LOOP [ <label> ] ;
Par exemple :
BEGIN
LET counter := 5;
LOOP
IF (counter = 0) THEN
BREAK;
END IF;
counter := counter - 1;
END LOOP;
RETURN counter;
END;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+-----------------+
L’exemple suivant crée une table de journal avec des entrées couvrant plusieurs dates. Elle utilise une LOOP pour archiver les lignes antérieures à une date limite dans une table d’archivage et les supprimer de la source, en traitant une journée à la fois jusqu’à ce qu’il ne reste aucune ligne éligible :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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 |
+---------------------+
Pour vérifier les résultats, interrogez les deux tables :
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 |
+----------+------------+-------------------+
Pour une syntaxe complète et des détails sur les boucles LOOP, voir LOOP (Exécution de scripts Snowflake).
Mettre fin à une boucle ou une itération
Dans une construction de boucle, vous pouvez spécifier quand la boucle ou une itération de la boucle doit se terminer prématurément. Les sections suivantes expliquent cela plus en détail :
Terminer une boucle
Vous pouvez explicitement mettre fin à une boucle de manière anticipée en exécutant la commande BREAK. BREAK (et son synonyme EXIT) arrête immédiatement l’itération en cours et ignore toutes les itérations restantes. Vous pouvez considérer BREAK comme un saut à la première instruction exécutable après la fin de la boucle.
BREAK est nécessaire dans une boucle LOOP mais ne l’est pas dans les boucles WHILE, FOR et REPEAT. Dans la plupart des cas, si vous souhaitez sauter des instructions, vous pouvez utiliser les constructions « branching » standard (Instructions IF et Instructions CASE) pour contrôler les instructions exécutées dans une boucle.
Une commande BREAK elle-même se trouve généralement à l’intérieur d’une instruction IF ou CASE.
Terminer une itération sans terminer la boucle
Vous pouvez utiliser la commande CONTINUE (ou ITERATE) pour sauter à la fin d’une itération d’une boucle, en ignorant les instructions restantes de la boucle. La boucle se poursuit au début de l’itération suivante.
De tels sauts sont rarement nécessaires. Dans la plupart des cas, si vous souhaitez sauter des instructions, vous pouvez utiliser les constructions « branching » standard (Instructions IF et Instructions CASE) pour contrôler les instructions exécutées dans une boucle.
Une commande CONTINUE ou ITERATE se trouve généralement à l’intérieur d’une instruction IF ou CASE.
Spécifier l’endroit où l’exécution doit se poursuivre après la fin de l’opération
Dans une commande BREAK ou CONTINUE, si vous devez poursuivre l’exécution à un point spécifique du code (par exemple, la boucle extérieure d’une boucle imbriquée), spécifiez une étiquette qui identifie le point auquel l’exécution doit se poursuivre.
L’exemple suivant en fait la démonstration dans une boucle imbriquée :
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;
Remarque : Si vous utilisez Snowflake CLI,:doc:SnowSQL </user-guide/snowsql>, la console classique ou la méthode execute_stream ou execute_string dans le code du Connecteur Python, utilisez cet exemple à la place (voir 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;
$$;
Dans cet exemple :
Il existe une boucle étiquetée INNER qui est imbriquée dans une boucle étiquetée OUTER.
CONTINUEOUTER lance une autre itération de la boucle avec la balise OUTER.
BREAK OUTER termine la boucle intérieure et transfère le contrôle à la fin de la boucle extérieure (étiquetée OUTER).
La sortie de cette commande est la suivante :
+-----------------+
| anonymous block |
|-----------------|
| [ |
| 0, |
| 5 |
| ] |
+-----------------+
Comme indiqué dans la sortie :
inner_counter est incrémenté jusqu’à 5. CONTINUE OUTER lance une nouvelle itération de la boucle externe, qui lance une nouvelle itération de la boucle interne, qui incrémente ce compteur jusqu’à 5. Ces itérations se poursuivent jusqu’à ce que la valeur de inner_counter soit égale à 5 et que BREAK OUTER mette fin à la boucle intérieure.
outer_counter n’est jamais incrémenté. L’instruction qui incrémente ce compteur n’est jamais atteinte car BREAK OUTER transfère le contrôle à la fin de la boucle externe.