Flexera logo
Image: How to: Create and use Snowflake stored procedures (2026)
This post originally appeared on the chaosgenius.io blog. Chaos Genius has been acquired by Flexera.

Snowflake stored procedures are named, callable units of procedural logic that let you bundle and store application logic directly inside Snowflake. They go well beyond a simple sequence of SQL commands. They give you branching, looping and error handling, all within a single callable routine. Once a stored procedure is created, you can call it as many times as you need, keeping your operations consistent and maintainable.

In this article, we’ll dive deep into Snowflake stored procedures, covering everything from basic definitions to advanced features and components. We’ll provide hands-on steps for creating Snowflake stored procedures in both Snowflake Scripting (SQL) and JavaScript. Plus, we’ll highlight the practicalities of calling these stored procedures in Snowflake.

Let’s dive in!

What are Snowflake stored procedures?

A Snowflake stored procedure is a set of logic you can call directly from SQL. Its main job is to perform database operations by executing multiple SQL statements in sequence, with control flow, variable management and exception handling fully baked in.

Stored procedures can run with privileges determined by the EXECUTE AS clause, which defaults to the procedure’s owner role rather than the caller’s role. That makes them useful for delegating controlled access without handing out broad privileges.

Common use cases include automating repetitive tasks (like purging records older than a given date), orchestrating multi-step data pipelines and encapsulating complex business logic that doesn’t belong in ad-hoc queries.

Supported languages for Snowflake stored procedures

Snowflake supports several programming languages for writing the logic of Snowflake stored procedures. These languages include:

Your choice depends on your team’s familiarity with the language, your existing codebase and which libraries or capabilities you need. In this article, we focus on Snowflake Scripting and JavaScript in depth.

Note: For Java, Python and Scala (Snowpark), the procedure syntax requires additional clauses like RUNTIME_VERSION, PACKAGES and HANDLER that aren’t needed for Snowflake Scripting or JavaScript inline handlers.

Snowflake stored procedure syntax: complete overview

The general pattern for creating a stored procedure looks like this:

CREATE OR REPLACE PROCEDURE <name> ( [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [,...] )

RETURNS <result_data_type>

LANGUAGE { SQL | JAVASCRIPT | JAVA | PYTHON | SCALA }

[ EXECUTE AS { CALLER | OWNER } ]

AS

$$

  <procedure_body>

$$;

Here’s what each clause does:

  • <name>: The procedure name. Must be a valid Snowflake identifier. If you need spaces or special characters, wrap it in double quotes.
  • ( [ <arg_name> <arg_data_type> ] [,…] ): Input parameters. Can be zero or more. Parameters can have default values, making them optional at call time.
  • RETURNS <result_data_type>: The SQL data type of the return value. Every CREATE PROCEDURE must include a RETURNS clause, even if the procedure doesn’t return anything meaningful.
  • LANGUAGE: Specifies the handler language. For Snowflake Scripting, this is SQL (and is actually optional—SQL is the default). For inline JavaScript, use JAVASCRIPT. Java, Python and Scala require additional clauses.
  • EXECUTE AS { CALLER | OWNER }: Controls which role’s privileges the procedure runs with. Defaults to OWNER.
  • <procedure_body>: The actual logic. For SQL and JavaScript, you write this inline between $$ delimiters (or single quotes). For Java, Python and Scala, you typically reference a handler class and method via the HANDLER clause.

Anatomy of a Snowflake stored procedure

Stored procedures in Snowflake are powerful tools that allow developers to encapsulate a series of SQL statements into a single callable routine. This not only promotes code reusability but also enhances the efficiency of SQL operations.

Basic CREATE PROCEDURE syntax

The CREATE PROCEDURE command is used to define a new stored procedure in Snowflake. This command allows you to specify the name of the procedure, its parameters and the body of the procedure, which contains the logic to be executed when the procedure is called.

For example:

CREATE OR REPLACE PROCEDURE sample_snowflake_stored_procedure()
	 RETURNS STRING
	 LANGUAGE JAVASCRIPT
	EXECUTE AS CALLER
	 AS '
	 return "Hello from the snowflake stored procedure!";
	 ';
Executing JavaScript-based Snowflake stored procedure - snowflake scripting - snowflake variables - stored procedures in Snowflake - snowflake stored procedure examples - snowflake javascript
Executing JavaScript-based Snowflake stored procedure – snowflake stored procedure

Overview of other stored procedure commands

1) Snowflake stored procedure syntax—ALTER PROCEDURE

The ALTER PROCEDURE command is used to modify an existing stored procedure. While you can’t change the body of the procedure directly with this command, you can use it to change the comment associated with the procedure or to set the owner.

For example:

Suppose you have a procedure named sample_snowflake_stored_procedure. To change its comment:

ALTER PROCEDURE sample_snowflake_stored_procedure() SET COMMENT = 'Updated comment for the snowflake stored procedure';
Updating comment for Snowflake stored procedure - snowflake scripting - snowflake variables - stored procedures in Snowflake - snowflake stored procedure examples - snowflake javascript
Updating comment for Snowflake stored procedure

2) Snowflake stored procedure syntax—SHOW PROCEDURES

The SHOW PROCEDURES command provides a list of Snowflake stored procedures in the current or specified schema or database.

For example:

To list all Snowflake stored procedures:

SHOW PROCEDURES;
Displaying list of Snowflake stored procedure - snowflake scripting - snowflake variables - stored procedures in Snowflake - snowflake stored procedure examples - snowflake javascript
Displaying list of Snowflake stored procedure

To list all procedures in a specific schema, say SCHEMA_STORED_PROCEDURE:

SHOW PROCEDURES IN SCHEMA SCHEMA_STORED_PROCEDURE;

3) Snowflake stored procedure syntax—DESCRIBE PROCEDURE

The DESCRIBE PROCEDURE command provides detailed information about a specific stored procedure, including its parameters, return type and body.

For example:

To describe the sample_snowflake_stored_procedure:

DESCRIBE PROCEDURE sample_snowflake_stored_procedure();
Describing details of Snowflake stored procedure - snowflake scripting - snowflake variables - stored procedures in Snowflake - snowflake stored procedure examples - snowflake javascript
Describing details of Snowflake stored procedure

4) Snowflake stored procedure syntax—CALL PROCEDURE

The CALL command is used to execute or invoke Snowflake stored procedures. You need to specify the procedure name and provide any required arguments.

For example:

Suppose you have a procedure named sample_snowflake_stored_procedure that accepts a name parameter. To call this procedure:

CALL sample_snowflake_stored_procedure();
Calling Snowflake stored procedure for execution - snowflake scripting - snowflake variables - stored procedures in Snowflake - snowflake stored procedure examples - snowflake javascript
Calling Snowflake stored procedure for execution

This would execute the sample_snowflake_stored_procedure procedure.

5) Snowflake stored procedure syntax—DROP PROCEDURE

The DROP PROCEDURE command is used to delete an existing stored procedure from the database. It’s essential to be certain about the procedure’s redundancy before executing this command.

For example:

To drop the sample_snowflake_stored_procedure :

DROP PROCEDURE IF EXISTS sample_snowflake_stored_procedure();

The IF EXISTS clause ensures that no error is thrown if the procedure doesn’t exist.

Dropping Snowflake Stored Procedures - snowflake scripting - snowflake variables - stored procedures in Snowflake - snowflake stored procedure examples - snowflake javascript
Dropping Snowflake Stored Procedures

Snowflake stored procedures naming conventions

While Snowflake doesn’t enforce strict naming conventions, it’s a best practice to adopt a consistent and descriptive naming pattern, which gurantees clarity and aids in easier management and invocation of procedures in the future.

Specifying return types in Snowflake stored procedures

When creating a stored procedure in Snowflake, it’s essential to specify the type of value it will return. This is done using the RETURNS keyword followed by the desired data type.

The return type ensures that the procedure produces the expected output, which can then be used or processed further. Common return types include STRING, NUMBER, FLOAT, BOOLEAN and various others.

Here are some common Snowflake stored procedures return types in JavaScript with examples:

See supported JavaScript data types in Snowflake.

1) Snowflake stored procedures return types—STRING

A Snowflake stored procedure can return a text value or string.

For example:

CREATE OR REPLACE PROCEDURE return_string_example()
	RETURNS STRING
	LANGUAGE JAVASCRIPT
	 AS '
	 return "Hello from the Snowflake stored procedure!";
	 ';

CALL return_string_example();
Creating and executing Snowflake JavaScript procedure - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating and executing Snowflake JavaScript procedure

When called, this Snowflake stored procedure will return the string “Hello from the Snowflake stored procedure!”.

2) Snowflake stored procedures return types—FLOAT

If you’re working with numeric values and wish to retain them as numbers, you can use the FLOAT data type.

For example:

CREATE OR REPLACE PROCEDURE return_float_example()
	RETURNS FLOAT
	 LANGUAGE JAVASCRIPT
	EXECUTE AS CALLER
	 AS '
	 return 42.0;
	 ';

CALL return_float_example();

This procedure will return the number 42 when called.

Creating and executing Snowflake Javascript procedure returning float - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating and executing Snowflake Javascript procedure returning float

3) Snowflake stored procedures return types—BOOLEAN

Boolean return types are useful for procedures that evaluate conditions and return either TRUE or FALSE.

For example:

CREATE OR REPLACE PROCEDURE is_even(num FLOAT)
	 RETURNS BOOLEAN
	LANGUAGE JAVASCRIPT
	 AS '
	 return (NUM % 2 === 0);
	';

CALL is_even(42);
Creating and executing Snowflake stored procedure to check even number - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating and executing a Snowflake stored procedure to check even numbers

For this procedure, if you call it with an even number (e.g., CALL is_even(42);), it will return TRUE. If you call it with an odd number, it will return FALSE.

4) Snowflake stored procedures return types— VARIANTS, OBJECTS and ARRAYS

Snowflake also supports more complex data types like VARIANT, OBJECT and ARRAY. These are especially useful when working with semi-structured data or when you need to return multiple values.

For example (Returning an ARRAY):

CREATE OR REPLACE PROCEDURE return_array_example()
	RETURNS ARRAY
	 LANGUAGE JAVASCRIPT
	EXECUTE AS CALLER
	 AS '
	 return [1, 2, 3, 4, 5];
	';

CALL return_array_example();

This procedure will return an array of numbers from 1 to 5.

Creating and executing Snowflake stored procedure returning an array - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating and executing Snowflake stored procedure returning an array

To learn more, Check out this list of all Data Type Mappings Between SQL and Handler Languages

Caller’s rights vs owner’s rights in Snowflake stored pocedures

Whenever a Snowflake stored procedure is executed, it runs with either the Caller’s Rights or the Owner’s Rights, but not both simultaneously.

  • Caller’s rights: The procedure runs with the privileges of whoever called it. It can access the caller’s session variables and current session context. If the caller lacks access to a table the procedure references, the call fails.
  • Owner’s rights: The procedure runs with the privileges of the role that owns it. This is the default. It lets the owner delegate specific tasks to other roles without granting those roles direct access to underlying objects.

Caller’s / Owner’s rights

When creating a stored procedure, you can specify whether it should run with Caller’s Rights or Owner’s Rights using the EXECUTE AS clause:

CREATE PROCEDURE procedure_name() 
LANGUAGE SQL
EXECUTE AS [CALLER | OWNER] 
AS $$ 
-- Procedure code here 
$$;

Caller’s / Owner’s Rights—Snowflake stored procedures code example

Let’s consider a simple example to demonstrate the difference between Caller’s and Owner’s Rights:

Suppose we have two roles in Snowflake: ROLE_1 and ROLE_2. Both roles have different privileges on a database named CLASSROOM and its STUDENTS table.

Scenario 1: Using Owner’s Rights

CREATE OR REPLACE PROCEDURE snowflake_stored_procedure_1()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS OWNER
AS
$$
DECLARE
		result VARCHAR;
BEGIN
		SELECT COUNT(*) INTO result FROM STUDENTS;
		RETURN result;
END;
$$;

Even if ROLE_2 does not have the privilege to view all data in the STUDENTS table, it can still execute the procedure if ROLE_1 (the owner) grants it the necessary privileges.

Scenario 2: Using Caller’s Rights

CREATE OR REPLACE PROCEDURE snowflake_stored_procedure_2()
RETURNS VARCHAR
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
DECLARE
		 result VARCHAR;
BEGIN
		 SELECT COUNT(*) INTO result FROM STUDENTS;
		 RETURN result;
END;
$$;

Here, if ROLE_2 does not have the necessary privileges on the STUDENTS table, it won’t be able to execute the procedure, even if ROLE_1 grants it the usage privilege.

Choosing between them

The decision to use Caller’s or Owner’s Rights depends on the specific requirements:

  • Owner’s Rights: Choose this if you want to delegate tasks to another user or role, allowing them to run with the owner’s privileges. It is useful when you want to provide limited access without granting broader privileges.
  • Caller’s Rights: Opt for this when the Snowflake stored procedure should operate only on objects that the caller owns or has the required privileges on. It is ideal when the procedure needs to use the caller’s environment, such as session variables.

Check out this documentation to learn more in-depth about Caller’s / Owner’s Rights.


Invoking Snowflake stored procedures

Stored procedures in Snowflake can be invoked using the CALL command. However, before you can call a stored procedure, you must ensure that your role has the USAGE privilege for that specific procedure.

Syntax:

CALL procedure_name(argument1, argument2, ...);

Privileges:

To invoke a stored procedure, the role you’re using must have the USAGE privilege. If you lack this privilege, you’ll encounter an authorization error.

Anonymous procedures:

Snowflake also supports anonymous procedures, which are procedures without a name. These can be both created and called using the CALL command. Notably, you don’t need a role with CREATE PROCEDURE schema privileges to work with anonymous procedures.

Specifying arguments

Stored procedures can accept multiple arguments. These arguments can be specified either by their name or their position.

For example:

Consider a stored procedure designed to concatenate three strings:

CREATE OR REPLACE PROCEDURE concatenate_strings(
		str1 VARCHAR,
		 str2 VARCHAR,
		str3 VARCHAR)
	 RETURNS VARCHAR
	LANGUAGE SQL
	AS
	$$
	BEGIN
		 RETURN str1 || str2 || str3;
	 END;
	 $$;
Creating Snowflake stored procedure to concatenate three strings - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure to concatenate three strings

Calling by name:

Arguments can be specified by their name, allowing flexibility in the order of specification.

CALL concatenate_strings(
	str1 => 'Hello there',
	 str3 => 'Snowflake stored procedure!',
	str2 => ' from ');
Calling Snowflake stored procedure to concatenate given strings - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Calling Snowflake stored procedure to concatenate given strings

Calling by position:

Alternatively, you can specify arguments based on their position in the procedure definition.

CALL concatenate_strings('Hello', ' from ', 'Snowflake stored procedure!');
Calling Snowflake stored procedure to concatenate provided strings - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Calling the Snowflake stored procedure to concatenate the provided strings

A few things you need to keep in mind:

  • Pick one style and stick to it. Do not mix name-based and positional arguments in the same call.
  • Don’t wrap argument names in double quotes when calling by name
  • If two procedures share a name but have different argument signatures, calling by name can help Snowflake resolve which one to run

Advanced invocation techniques

Expressions as Arguments:

Snowflake allows the use of general expressions as arguments. For instance:

CALL sample_procedure(3 * 7.14::FLOAT);

Subqueries as Arguments:

You can also use subqueries as arguments:

CALL sample_procedure(SELECT AVG(price) FROM products);

Snowflake stored procedures limitations:

  • Only one stored procedure can be called per CALL statement.
  • Stored procedure calls cannot be part of an expression or combined with other calls in a single statement.
  • While you can’t use a stored procedure call as part of an SQL expression, within a stored procedure, you can invoke another stored procedure or even call the procedure recursively.

Note: Recursive or nested calls can lead to exceeding the maximum allowed stack depth. It’s crucial to be cautious when nesting calls or using recursion to avoid potential stack overflow errors.

Creating Snowflake stored procedures with Snowflake Scripting—each component explained

1) Variables in Snowflake stored procedures

What are variables in Snowflake stored procedures?

Snowflake variables are a named object that can hold a value of a specific data type. The value held in a variable can change during the execution of a stored procedure. Variables are used in Snowflake stored procedures to store results that can be referenced multiple times within the Snowflake stored procedure.

Unlike regular programming languages, variables in Snowflake scripting (SQL) do not need to be declared before they are used. However, it is considered a good practice to declare all variables at the beginning of the Snowflake stored procedure. Declaring variables makes the code more readable and helps avoid any kind of bugs in future.

Key facts:

  • Variables can hold values of any Snowflake data type like NUMBER, VARCHAR, DATE, etc.
  • Variables are local to the stored procedure in which they are declared.
  • Variable values persist only for the duration of stored procedure execution. Once the procedure finishes execution, the values are lost.
  • Variables can be used anywhere in the stored procedure.

Declaring Snowflake variables in Snowflake stored procedures

It is highly recommended to declare all the variables before using them in a stored procedure. Declaring variables explicitly specifies the name and data type which makes the code more readable.

Note: If you can set an initial value using the DEFAULT keyword and Snowflake will automatically determine the variable’s data type.

You can declare a Snowflake variables:

By declaration in the DECLARE Section

DECLARE
	 variable_name data_type;
	 variable_name DEFAULT <expression>;
	variable_name data_type DEFAULT <expression>;

For example:

DECLARE
	total_sales NUMBER(38,2);
	 total_sales DEFAULT 100.00;
	total_sales NUMBER(38,2) DEFAULT 100.00;

By declaration in the BEGIN…END Section

In the BEGIN…END section of the body, variables need to be introduced by the LET command when declaring them.

BEGIN
	 LET variable_name := <expression>;
	 LET variable_name DEFAULT <expression>;
	LET variable_name data_type := <expression>;
	LET variable_name data_type DEFAULT <expression>;
END;

For example:

BEGIN
	LET total_sales := 100.00;
	LET total_sales DEFAULT 100.00;
	 LET total_sales NUMBER(38,2) := 100.00;
	LET total_sales NUMBER(38,2) DEFAULT 100.00;
END;

Assigning values to variables in Snowflake stored procedures

Once a variable is declared, you can assign a value to it using the “:=” operator. You can also use other variables in the expression to compute the value.

Syntax Overview:
variable_name := expression;

For example:

DECLARE
	 net_profit NUMBER(38, 2) DEFAULT 0.0;
BEGIN
	 LET revenue NUMBER(38, 2) := 200.00;
	 LET expenses NUMBER(38, 2) DEFAULT 50.00;

	net_profit := revenue - expenses;

	 RETURN net_profit;
END;
Full code:
CREATE OR REPLACE PROCEDURE calculate_net_profit()
	RETURNS FLOAT
	 LANGUAGE SQL
AS
$$
DECLARE
	net_profit NUMBER(38, 2) DEFAULT 0.0;
BEGIN
	LET revenue NUMBER(38, 2) := 200.00;
	LET expenses NUMBER(38, 2) DEFAULT 50.00;

	 net_profit := revenue - expenses;

	RETURN net_profit;
END;
$$;

-- Call the stored procedure to calculate net profit
CALL calculate_net_profit();
Creating and executing Snowflake stored procedure to calculate net profit - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating and executing Snowflake stored procedure to calculate net profit

Variable binding in SQL statements

Variables can be used in SQL statements by prefixing them with a colon (:).

For example:

DELETE FROM CUSTOMERS WHERE CUSTOMER_ID = :customer_id;

If the variable represents an object name, use the IDENTIFIER keyword:

DELETE FROM IDENTIFIER(:table_name) WHERE ID = :record_id;

Using the INTO clause to assign SQL results to variables

You can use the INTO clause to assign the result of a SQL query to a variable.

Syntax overview:

SELECT expression1, expression2 INTO :variable1, :variable2 FROM table WHERE condition;

For example:

DECLARE
	 employee_id INTEGER;
	 employee_name VARCHAR;
BEGIN
	SELECT id, name INTO :employee_id, :employee_name FROM EMPLOYEES WHERE id = 1;
	RETURN employee_id || ' ' || employee_name;
END;

Variable scope in Snowflake Stored Procedures

In Snowflake stored procedures with nested blocks, variables are scoped to the block in which they are declared. Snowflake searches for variables starting from the innermost block and moving outward.

For example:

DECLARE
	 my_var NUMBER(38, 2) := 5;
BEGIN
	DECLARE
		 my_var NUMBER(38, 2) := 7;
	 -- Here, my_var is 7
	 END;
-- Here, my_var is 5
END;

Full code:

CREATE OR REPLACE PROCEDURE variable_scope_example()
	RETURNS STRING
	LANGUAGE SQL
AS
$$
DECLARE
	 result_string STRING DEFAULT '';
	 my_var NUMBER(38, 2) := 5;
BEGIN
	-- Outer block
	result_string := result_string || 'Outer block my_var: ' || my_var || 'n';

	DECLARE
		 my_var NUMBER(38, 2) := 7;
	 BEGIN
		-- Inner block
		result_string := result_string || 'Inner block my_var: ' || my_var || 'n';
	END;

	-- Outer block again
	result_string := result_string || 'After inner block, outer block my_var: ' || my_var;

	RETURN result_string;
END;
$$;

CALL variable_scope_example();
Creating and executing Snowflake stored procedure demonstrating variable scope - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating and executing Snowflake stored procedure demonstrating variable scope

2) Cursor declarations in Snowflake stored procedure

Cursor in Snowflake stored procedures acts as a control structure that enables traversal over the records in a database. Think of it as a pointer to one row in a set of rows. It’s like an iterator in programming languages, allowing you to loop through a set of rows from a query result set, processing one row at a time.

Working with Cursors in Snowflake stored procedures

The process of working with cursors in Snowflake stored procedures can be broken down into a series of steps:

  • Declaration: Before a cursor can be used, it must be declared. This involves naming the cursor and associating it with a SELECT statement.
  • Opening: Once declared, a cursor needs to be opened using the OPEN command. This step is crucial as the associated query isn’t executed until the cursor is opened.
  • Fetching: After opening the cursor, you can retrieve rows from it using the FETCH command. Each FETCH operation retrieves a single row from the result set.
  • Closing: After all rows have been fetched, the cursor should be closed using the CLOSE command to free up resources.

Setting up the data for the examples

Before diving into the cursor operations, let’s set up some sample data:

CREATE OR REPLACE TABLE books (book_id INTEGER, title STRING, price NUMBER(12, 2));
INSERT INTO books (book_id, title, price) VALUES
	 (1, 'The Great Gatsby', 15.99),
	(2, 'Moby Dick', 12.49),
	(3, 'Pride and Prejudice', 9.99);
Creating 'books' table and inserting sample data in Snowflake - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating ‘books’ table and inserting sample data in Snowflake

Declaring a Cursor

You can declare a cursor in the Snowflake stored procedure either in the DECLARE section or within the BEGIN … END block of a stored procedure. Here are some examples:

Using the DECLARE section

-- Stored Procedure with Cursor Declaration using DECLARE
CREATE OR REPLACE PROCEDURE cursor_declare_example()
	RETURNS STRING
	LANGUAGE SQL
AS
$$
DECLARE
	 c1 CURSOR FOR SELECT title, price FROM books WHERE price > 10;
	result_string STRING DEFAULT '';
BEGIN
	 -- Sample operations with c1 can be added here
	 RETURN result_string;
END;
$$;
-- Call the stored procedure
CALL cursor_declare_example();

Using the BEGIN … END block

CREATE OR REPLACE PROCEDURE cursor_begin_end_example()
	RETURNS STRING
	LANGUAGE SQL
AS
$$
DECLARE
	 result_string STRING DEFAULT '';
BEGIN
	LET c2 CURSOR FOR SELECT title FROM books WHERE price <= 10;
	 -- Sample operations with c2 can be added here
	 RETURN result_string;
END;
$$;
-- Call the stored procedure
CALL cursor_begin_end_example();

Using Bind parameters

You can also use bind parameters in the cursor declaration and bind them when opening the cursor:

CREATE OR REPLACE TABLE invoices (id INTEGER, price NUMBER(12, 2));

INSERT INTO invoices (id, price) VALUES
	 (1, 21.11),
	(2, 25.22),
	 (3, 29.99),
	(4, 35.50);
-- Stored Procedure with Bind Parameters in Cursor Declaration
CREATE OR REPLACE PROCEDURE bind_parameters_example()
	RETURNS INTEGER
	 LANGUAGE SQL
AS
$$
DECLARE
	id INTEGER DEFAULT 0;
	 min_price NUMBER(13,2) DEFAULT 22.00;
	max_price NUMBER(13,2) DEFAULT 33.00;
	 c1 CURSOR FOR SELECT id FROM invoices WHERE price > ? AND price < ?;
BEGIN
	OPEN c1 USING (min_price, max_price);
	 FETCH c1 INTO id;
	RETURN id;
END;
$$;
CALL bind_parameters_example();
Creating 'invoices' table, inserting data and executing Snowflake stored procedure with bind parameters - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating ‘invoices’ table, inserting data and executing Snowflake stored procedure with bind parameters

Opening a Cursor

To execute the query and load the results into the cursor, you need to open it using the OPEN command:

OPEN c1;

Fetching data with Cursor

To fetch data from the cursor, use the FETCH command:

FETCH c1 INTO variable_for_column_value;

Closing a Cursor

Once you’re done fetching the data, it’s good practice to close the cursor:

CLOSE c1;

Complete example—summing prices using Snowflake cursor

Here’s a complete example that sums the prices of books from two rows:

CREATE OR REPLACE TABLE books (title STRING, price FLOAT);

-- Insert some sample data into the table
INSERT INTO books VALUES ('Great Gatsby', 25.0), ('Mockingbird', 15.5), ('Pride + Prejudice', 12.25);

-- Create a stored procedure that uses a cursor to sum the prices of two books
CREATE OR REPLACE PROCEDURE calculate_total_price()
	RETURNS FLOAT
	 LANGUAGE SQL
AS
$$
DECLARE
		row_price FLOAT;
		total_price FLOAT;
		c1 CURSOR FOR SELECT price FROM books;
BEGIN
		 row_price := 0.0;
		total_price := 0.0;
		 OPEN c1;
		 FETCH c1 INTO row_price;
		 total_price := total_price + row_price;
		FETCH c1 INTO row_price;
		total_price := total_price + row_price;
		 CLOSE c1;
		RETURN total_price;
END;
$$;

-- Call the stored procedure to see the results
CALL calculate_total_price();
Creating 'books' table, inserting data and executing Snowflake stored procedure to sum prices of two books - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating ‘books’ table, inserting data and executing Snowflake stored procedure to sum prices of two books

Troubleshooting:

Symptom: Cursor Skips Rows

Possible Cause: You might have executed FETCH inside a FOR <record> IN <cursor> loop, which automatically fetches the next row.

Solution: Remove any redundant FETCH commands inside the loop.

 

Symptom: Unexpected NULL Values

Possible Cause: If you have an odd number of rows and you execute an extra FETCH inside the loop, you’ll get NULL values.

Solution: Again, remove any redundant FETCH commands inside the loop.

3) Branching construct (IF-ELSE and CASE) in Snowflake stored procedure

Snowflake stored procedures offer a robust set of branching constructs that allow developers to control the flow of execution based on specific conditions.

IF Statement

The IF statement in Snowflake is a conditional branching mechanism that allows specific code blocks to be executed based on whether a given condition is true or false.

Syntax:
IF (condition) THEN
		-- statements to execute if condition is true
ELSEIF (another_condition) THEN
		-- statements to execute if another_condition is true
ELSE
		 -- statements to execute if no conditions are met
END IF;

For example:

Let’s consider a scenario where we want to determine the category of a product based on its price:

CREATE OR REPLACE PROCEDURE product_category(price FLOAT)
	 RETURNS VARCHAR
	LANGUAGE SQL
AS
$$
	DECLARE
		 category VARCHAR;
	BEGIN
		 IF (price < 50) THEN
			category := 'Budget';
		 ELSEIF (price >= 50 AND price < 150) THEN
			category := 'Mid-range';
		ELSE
			category := 'Premium';
		END IF;
		 RETURN category;
	 END;
$$
;

CASE Statement

The CASE statement in Snowflake provides a way to perform conditional logic based on specific values or conditions.

Searched CASE statement:

This form of the CASE statement evaluates multiple conditions and returns a value when the first condition is met.

Syntax:

CASE
		WHEN condition1 THEN
				-- statements for condition1
		WHEN condition2 THEN
				-- statements for condition2
		ELSE
				-- default statements
END;

For example:

Let’s determine the shipping cost based on the weight of a package:

CREATE OR REPLACE PROCEDURE shipping_cost(weight FLOAT)
	RETURNS FLOAT
	 LANGUAGE SQL
AS
$$
	 DECLARE
		cost FLOAT;
	 BEGIN
		CASE
			WHEN weight <= 1 THEN
				cost := 5.0;
			WHEN weight > 1 AND weight <= 5 THEN
				cost := 10.0;
			 ELSE
				 cost := 20.0;
		END;
		RETURN cost;
	END;
$$
;

CALL shipping_cost(1.1);
Creating Snowflake stored procedure in Snowflake to calculate shipping cost based on weight and then calling it - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating a Snowflake stored procedure in Snowflake to calculate shipping cost based on weight and then calling it

Simple CASE statement:

This form evaluates a single expression against multiple values.

Syntax:

CASE expression
		WHEN value1 THEN
				-- statements for value1
		WHEN value2 THEN
				-- statements for value2
		ELSE
				-- default statements
END;

For example:

Let’s categorize a student’s performance based on their grade:

CREATE OR REPLACE PROCEDURE student_performance(grade CHAR)
	 RETURNS VARCHAR
	LANGUAGE SQL
AS
$$
	DECLARE
		 performance VARCHAR;
	 BEGIN
		CASE grade
			WHEN 'A' THEN
				 performance := 'Excellent';
			WHEN 'B' THEN
				 performance := 'Good';
			 WHEN 'C' THEN
				performance := 'Average';
			 ELSE
				 performance := 'Needs Improvement';
		END;
		RETURN performance;
	 END;
$$
;


CALL student_performance('B');
Creating Snowflake stored procedure in Snowflake to evaluate student performance based on grade and then calling it - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure in Snowflake to evaluate student performance based on grade and then calling it

4) Looping in Snowflake stored procedure

Looping is a fundamental concept in programming, allowing for a set of instructions to be executed repeatedly based on a condition or a set number of times. Snowflake Stored Procedures support various looping constructs, each with its unique characteristics and use cases.

Snowflake Scripting supports the following types of loops:

FOR Loop in Snowflake stored procedures

The FOR loop in Snowflake is designed to iterate a set number of times, making it ideal for situations where the number of iterations is known beforehand.

Syntax:
FOR counter_variable IN [REVERSE] start TO end DO
		 statement;
END FOR;

Points to be noted:

  • The loop will iterate from the start value to the end value.
  • The optional REVERSE keyword allows the loop to iterate in reverse order.
  • The loop counter is independent of any variable declared outside the loop with the same name.

Example: Sum of first N natural numbers

CREATE OR REPLACE PROCEDURE sum_of_n_numbers(n INTEGER)
	 RETURNS INTEGER
	LANGUAGE SQL
AS
$$
	DECLARE
		 sum INTEGER DEFAULT 0;
	 BEGIN
		FOR i IN 1 TO n DO
			sum := sum + i;
		 END FOR;
		 RETURN sum;
	END;
$$
;

To call this procedure:

-- Calling the procedure
CALL sum_of_n_numbers(5);	 
Creating Snowflake stored procedure to calculate the sum of the first 'n' numbers - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure to calculate the sum of the first ‘n’ numbers

WHILE Loop in Snowflake stored procedures

The WHILE loop is condition-based, meaning it will continue to iterate as long as a specified condition remains true.

Syntax:
WHILE (condition) DO
		statement;
END WHILE;

Points to be noted:

  • The loop will continue as long as the condition evaluates to TRUE.
  • It’s essential to ensure that the condition eventually becomes FALSE; otherwise, an infinite loop can occur.

Example: Factorial of a Number

CREATE OR REPLACE PROCEDURE factorial(n INTEGER)
RETURNS INTEGER
LANGUAGE SQL
AS
$$
DECLARE
		result INTEGER;		-- Stores the factorial result.
BEGIN
		result := 1;
		WHILE (n > 1) DO
				 result := result * n;
				n := n - 1;
		 END WHILE;
		 RETURN result;
END;
$$
;

To call this procedure:

-- Calling the procedure
CALL factorial(5);	 -- Returns 120
Creating Snowflake stored procedure in Snowflake to calculate factorial of a number - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure in Snowflake to calculate factorial of a number

REPEAT Loop in Snowflake stored procedures

The REPEAT loop, akin to the DO-WHILE loop in other languages, will always execute at least once before checking its condition.

Syntax:
REPEAT
		 statement;
UNTIL (condition)
END REPEAT;

Points to be noted:

  • The loop will continue until the condition becomes TRUE.
  • The condition is checked after the loop’s body has executed.

Example: Counting digits in a number

CREATE OR REPLACE PROCEDURE count_digits(num INTEGER)
RETURNS INTEGER
LANGUAGE SQL
AS
$$
DECLARE
		 count INTEGER DEFAULT 0;
BEGIN
		REPEAT
				count := count + 1;
				 num := num / 10;
		 UNTIL (num = 0)
		END REPEAT;
		 RETURN count;
END;
$$
;

To call this procedure:

-- Calling the procedure
CALL count_digits(12345);	 -- Returns 5
Creating Snowflake stored procedure to count the number of digits in an integer - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure to count the number of digits in an integer

LOOP in Snowflake stored procedures

The LOOP construct is the most basic loop in Snowflake, requiring an explicit exit condition using the BREAK command.

Syntax:

LOOP
		 statement;
		 IF (exit_condition) THEN
				 BREAK;
		 END IF;
END LOOP;

Points to be noted:

  • The loop will continue indefinitely unless a BREAK command is executed.
  • It’s essential to provide an exit condition to prevent infinite loops.

Example: Generating a Fibonacci series

CREATE OR REPLACE PROCEDURE fibonacci_series(n INTEGER)
	RETURNS VARCHAR
	 LANGUAGE SQL
AS
$$
	 DECLARE
		a INTEGER DEFAULT 0;
		b INTEGER DEFAULT 1;
		next INTEGER;
		 series VARCHAR DEFAULT '0, 1';
	 BEGIN
		LOOP
			next := a + b;
			IF next > n THEN
				 BREAK;
			 END IF;
			series := series || ', ' || next::VARCHAR;
			a := b;
			 b := next;
		 END LOOP;
		RETURN series;
	END;
$$
;

To call this procedure:

-- Calling the procedure
CALL fibonacci_series(100);	 -- Returns "0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89"
Creating table and Snowflake stored procedure in Snowflake to generate Fibonacci series, then calling it and displaying the results - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating table and Snowflake stored procedure in Snowflake to generate Fibonacci series, then calling it and displaying the results

5). RESULTSETs in Snowflake stored procedure

RESULTSET in Snowflake is a data type that allows users to store and manipulate the result set of a SELECT statement within Snowflake stored procedures. This powerful feature provides flexibility in handling query results, whether you want to return them as a table or iterate over them using cursors.

What is RESULTSET ?

A RESULTSET in Snowflake is a pointer to the result set of a query. Unlike traditional variables that store single values, a RESULTSET can hold multiple rows of data. This makes it particularly useful for procedures that need to work with or return multiple rows of data.

Syntax 

Declaring a RESULTSET

A RESULTSET can be declared in two main ways:

1) Using the DECLARE section:

DECLARE
		 result_name RESULTSET DEFAULT (query);

2) Within the BEGIN…END block:

BEGIN
		 LET result_name := (query);
END;

Accessing Data from a RESULTSET

Once the RESULTSET is declared, the data in a RESULTSET can be accessed in two primary ways:

Returning as a Table: By using the TABLE() function, the data in the RESULTSET can be returned as a table.

RETURN TABLE(result_name);

Using a Cursor: A cursor can be used to iterate over the rows in a RESULTSET.

LET cursor_name CURSOR FOR result_name;

Practical examples of RESULTSETs in Snowflake stored procedure

Returning Data as a Table

Consider a scenario where you have a table named EMPLOYEES and you want to return all employee names with their IDs. Here’s how you can use a RESULTSET:

CREATE TABLE IF NOT EXISTS EMPLOYEES (
		 ID NUMBER PRIMARY KEY,
		 EMP_NAME VARCHAR
);
-- Insert sample data into EMPLOYEES table
INSERT INTO EMPLOYEES (ID, EMP_NAME) VALUES (1, 'Chaos'), (2, 'Genius');
-- Create the stored procedure to fetch employees
CREATE OR REPLACE PROCEDURE fetch_employees()
RETURNS TABLE(ID NUMBER, NAME VARCHAR)
LANGUAGE SQL
AS
$$
		 DECLARE
				emp_data RESULTSET DEFAULT (SELECT ID, EMP_NAME FROM EMPLOYEES);
		BEGIN
				 RETURN TABLE(emp_data);
		END;
$$
;
-- Calling the procedure
CALL fetch_employees();
Creating 'EMPLOYEES' table, inserting sample data and executing Snowflake stored procedure in Snowflake to fetch employee details - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating ‘EMPLOYEES’ table, inserting sample data and executing the stored procedure

Using a cursor with RESULTSET

If you wish to iterate over the rows of a RESULTSET, you can use a cursor. Here’s an example that fetches the names of employees and appends a prefix “Mr./Ms.” based on some criteria:

CREATE OR REPLACE PROCEDURE prefix_employees()
RETURNS TABLE(NAME VARCHAR)
LANGUAGE SQL
AS
$$
		DECLARE
				 emp_data RESULTSET DEFAULT (SELECT EMP_NAME FROM EMPLOYEES);
				 cur CURSOR FOR emp_data;
				 name VARCHAR;
				prefixed_name VARCHAR;
		BEGIN
				 OPEN cur;
				LOOP
						FETCH cur INTO name;
						IF name LIKE '%a' THEN
								prefixed_name = 'Ms. ' || name;
						 ELSE
								 prefixed_name = 'Mr. ' || name;
						END IF;
						 INSERT INTO result_table VALUES (prefixed_name);
				 END LOOP;
				CLOSE cur;
				RETURN TABLE(result_table);
		 END;
$$
;

What is the difference between RESULTSET vs CURSOR?

Both give you access to query results, but they serve different purposes:

  • Iteration: Cursors are designed for row-by-row processing. A RESULTSET is better suited for storing and returning full result sets.
  • Execution timing: The query assigned to a RESULTSET executes immediately on assignment. For a cursor, the query runs only when you call OPEN.
  • Bind variables: Cursors support binding variables (via OPEN … USING); RESULTSET doesn’t.

6) Handling exceptions in Snowflake stored procedures

Exceptions are inevitable when working with stored procedures in Snowflake. They occur when a piece of code encounters an issue that it cannot resolve during execution. Snowflake offers robust features for declaring, raising and handling exceptions in stored procedures.

Declaring an exception

In Snowflake, you can declare your own exceptions in the DECLARE section of a stored procedure. The syntax for declaring an exception is as follows:

Syntax:

DECLARE
	 exception_name EXCEPTION (exception_number, 'exception_message');
  • exception_name: The name you give to the exception.
  • exception_number: A unique identifier for the exception, ranging from -20000 to -20999.
  • exception_message: A text description of the exception.

Here’s a simple example:

DECLARE
	 DIVIDE_BY_ZERO_EXCEPTION EXCEPTION (-20001, 'Division by zero is not allowed.');

Raising an exception

Once an exception is declared, you can raise it manually using the RAISE command. The syntax is:

Syntax:

RAISE exception_name;

Here’s a simple example:

Here’s a code snippet that raises a custom exception:

CREATE OR REPLACE PROCEDURE raise_custom_exception()
RETURNS STRING
LANGUAGE SQL
AS
$$
	 DECLARE
		DIVIDE_BY_ZERO_EXCEPTION EXCEPTION (-20001, 'Division by zero is not allowed.');
	BEGIN
		 RAISE DIVIDE_BY_ZERO_EXCEPTION;
	END;
$$;
Creating Snowflake stored procedure to raise a custom exception - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure to raise a custom exception

Catching an exception

Snowflake allows you to catch exceptions using the EXCEPTION block. The syntax is:

Syntax:

BEGIN
	 -- code
EXCEPTION
	 WHEN exception_name THEN
		 -- handle exception
END;

Here’s a simple example:

Here’s how you can catch a custom exception:

CREATE OR REPLACE PROCEDURE catch_custom_exception()
RETURNS STRING
LANGUAGE SQL
AS
$$
	 DECLARE
		DIVIDE_BY_ZERO_EXCEPTION EXCEPTION (-20001, 'Division by zero is not allowed.');
	BEGIN
		 RAISE DIVIDE_BY_ZERO_EXCEPTION;
	EXCEPTION
		 WHEN DIVIDE_BY_ZERO_EXCEPTION THEN
			 RETURN 'Caught a division by zero exception';
	END;
$$;
Creating Snowflake stored procedure to raise and catch a custom exception for division by zero - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure to raise and catch a custom exception for division by zero

Built-in exception variables

Inside an exception handler, Snowflake populates three variables automatically:

  • SQLCODE — the exception number
  • SQLERRM — the error message
  • SQLSTATE — a 5-character status code

Here’s a simple example:

EXCEPTION
	WHEN DIVIDE_BY_ZERO_EXCEPTION THEN
		RETURN SQLSTATE || ':' || SQLCODE || ':' || SQLERRM;

Built-in exceptions

Snowflake has predefined exceptions like STATEMENT_ERROR, EXPRESSION_ERROR and OTHER. These can be used alongside custom exceptions.

Here’s a simple example:
EXCEPTION
	WHEN STATEMENT_ERROR THEN
		 RETURN 'Statement Error Occurred';
	 WHEN OTHER THEN
		RETURN 'An unknown error occurred';

Advanced exception handling

You can also handle multiple exceptions using OR and even raise the same exception within an exception handler using RAISE without arguments.

Here’s a simple example:
EXCEPTION
	 WHEN DIVIDE_BY_ZERO_EXCEPTION OR STATEMENT_ERROR THEN
		-- Capture details
		RAISE;	-- Re-raise the caught exception

7) EXECUTE IMMEDIATE in Snowflake stored procedures

EXECUTE IMMEDIATE command allows for the dynamic execution of SQL statements that are formulated as string literals. This can include:

  • A single SQL statement
  • A stored procedure call
  • A control-flow statement
  • A block
Syntax:
EXECUTE IMMEDIATE '<SQL_statement>';

Executing SQL statements using EXECUTE IMMEDIATE

To execute a simple SQL query, you can use EXECUTE IMMEDIATE as follows:

EXECUTE IMMEDIATE 'SELECT AVG(salary) FROM employee_data';
Executing dynamic SQL to calculate average salary from 'employee_data' in Snowflake - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Executing dynamic SQL to calculate average salary from ’employee_data’ in Snowflake

This will execute the SQL query encapsulated within the string, calculating the average salary from the employee_data table.

Invoking stored procedures with EXECUTE IMMEDIATE

Stored procedures can also be invoked dynamically using EXECUTE IMMEDIATE. Here’s how:

Syntax:

EXECUTE IMMEDIATE 'CALL procedure_name()';

Here’s a simple example:

EXECUTE IMMEDIATE 'CALL calculate_bonus()';
Executing dynamic SQL to call the 'calculate_bonus' Snowflake stored procedure - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Executing dynamic SQL to call the ‘calculate_bonus’ Snowflake stored procedure

As you can see, the Snowflake stored procedure named calculate_bonus() will be invoked when the EXECUTE IMMEDIATE statement is executed.

Running an anonymous block

If you’re using Snowsight, you can run anonymous blocks directly. However, in SnowSQL or the classic web interface, you’ll need to use EXECUTE IMMEDIATE.

EXECUTE IMMEDIATE
$$
	DECLARE
		 total_sales FLOAT;
	 BEGIN
		total_sales := 2;
		 RETURN total_sales * 2;
	END;
$$;
Executing dynamic SQL block to calculate double of total sales - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Executing a dynamic SQL block to calculate double of total sales

This anonymous block immediately calculates total_sales and returns it.

Using the USING clause

The USING clause allows you to pass variables into the SQL statement being executed.

Syntax:

EXECUTE IMMEDIATE '<SQL_query>' USING (variable1, variable2, ...);

Here’s a simple example:

CREATE OR REPLACE PROCEDURE filter_data()
	RETURNS STRING
	LANGUAGE SQL
AS
$$
	DECLARE
		 sql_text VARCHAR DEFAULT 'DELETE FROM orders WHERE order_date = ?';
		target_date DATE DEFAULT '2022-01-01';
	BEGIN
		 EXECUTE IMMEDIATE sql_text USING (target_date);
		RETURN 'Data deleted for ' || target_date;
	END;
$$;
Creating Snowflake stored procedure to filter and delete data based on a target date - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating Snowflake stored procedure to filter and delete data based on a target date

You can see that the stored procedure deletes orders for a specific date, passed as a variable.

Step-by-step guide to create Snowflake stored procedures in JavaScript

Snowflake’s support for JavaScript as a stored procedure language opens up a world of possibilities for developers familiar with the language. This step will walk you through the process of creating Snowflake stored procedures using Snowflake JavaScript, ensuring you have a comprehensive understanding of each step.

Note: While Snowflake primarily uses SQL for stored procedures, it also supports JavaScript, offering greater flexibility and functionality.

Prerequisites

  • A Snowflake account with the necessary privileges
  • Basic knowledge of SQL and JavaScript

Creating your first Snowflake JavaScript stored procedure

Step 1—Setting up the procedure

Start by defining the procedure using the CREATE PROCEDURE statement. Specify the name, return type and language.

CREATE OR REPLACE PROCEDURE sample_procedure()
	RETURNS STRING
	LANGUAGE JAVASCRIPT
	 EXECUTE AS CALLER
	AS
	$$ 
	 // JavaScript code goes here
	 $$
;

Step 2—Adding JavaScript logic

Within the $$ delimiters, you can write your JavaScript code. For this example, let’s create a simple procedure that returns a greeting.

var greeting = "Hello there from Snowflake JavaScript!";
return greeting;
Creating JavaScript Snowflake stored procedure in Snowflake returning a greeting - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating JavaScript Snowflake stored procedure in Snowflake returning a greeting

Step 3—Calling the procedure

Invoke the stored procedure using the CALL statement:

CALL sample_procedure();
Calling Snowflake JavaScript stored procedure for a greeting - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Calling Snowflake JavaScript stored procedure for a greeting

Passing parameters in Snowflake JavaScript stored procedure

Stored procedures often require input parameters to perform operations. Let’s explore how to pass and use parameters in our Snowflake JavaScript stored procedure.

Step 1—Define the parameters

When creating the procedure, specify the parameters and their data types:

CREATE OR REPLACE PROCEDURE greet_user(name STRING)
	RETURNS STRING
	LANGUAGE JAVASCRIPT
	 EXECUTE AS CALLER
	AS
	$$
		var greeting = "Hello, " + NAME + "! Welcome to Snowflake!";
		return greeting;
	$$
;
Creating JavaScript Snowflake stored procedure in Snowflake returning a greeting - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating JavaScript Snowflake stored procedure in Snowflake to greet a user by name

Step 2—Calling the procedure with parameters

Invoke the procedure, passing the necessary arguments:

CALL greet_user('Chaos Genius');
Calling Snowflake stored procedure to greet "Chaos Genius" - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Calling Snowflake stored procedure to greet “Chaos Genius”

Working with Snowflake functions

You can execute SQL statements within your JavaScript stored procedure using Snowflake’s built-in JavaScript functions.

Step 1—Using snowflake.execute()

To run a SQL statement, use the snowflake.execute() function. For instance, to fetch data from a table:

var resultSet = snowflake.execute({sqlText: "SELECT * FROM my_table"});

Step 2—Processing the results

You can iterate over the result set and process the data:

while (resultSet.next()) {
		var data = resultSet.getColumnValue(1);
		 // Process data
}

Error handling

JavaScript’s try..catch construct allows you to handle errors gracefully in your stored procedures.

try {
		// Code that might throw an exception
} catch(err) {
		 return "An error occurred: " + err; 
}

Debugging and logging

Debugging is crucial for identifying issues in your Snowflake JavaScript stored procedures. Use console.log() to print messages, which can be viewed in Snowflake’s history:

console.log("This is a debug message.");

Here’s a simple example:

CREATE TABLE my_table (
		 id INT AUTOINCREMENT PRIMARY KEY,
		data VARCHAR
);

-- Populate the table with sample data
INSERT INTO my_table (data) VALUES ('Sample Data 1'), ('Sample Data 2'), ('Sample Data 3');

CREATE OR REPLACE PROCEDURE fetch_and_process_data()
		 RETURNS STRING
		 LANGUAGE JAVASCRIPT
		EXECUTE AS CALLER
AS
$$
try {
		// Step 1--Using snowflake.execute()
		var resultSet = snowflake.execute({sqlText: "SELECT * FROM my_table"});

		 // Step 2--Processing the Results
		var output = "";
		while (resultSet.next()) {
				var data = resultSet.getColumnValue(1);
				 output += data + ", "; // Process data
		 }

		// Debugging and Logging
		console.log("Data fetched and processed.");

		 return output;

} catch(err) {
		 return "An error occurred: " + err; 
}
$$;

-- Calling the stored procedure to fetch and process data
CALL fetch_and_process_data();
Creating table, inserting data and executing JavaScript Snowflake stored procedure in Snowflake to fetch and process data - snowflake scripting - snowflake variables - stored procedures in snowflake - snowflake stored procedure examples - snowflake javascript
Creating table, inserting data and executing JavaScript Snowflake stored procedure in Snowflake to fetch and process data

Check out this in-depth playlist by Data Engineering Simplified to learn everything about Snowflake stored procedures, from basic to advanced.

Best practices for creating Snowflake stored procedures

Modularity. Break complex procedures into smaller, reusable units. A procedure that does one thing well is easier to test and maintain than a monolith that does everything.

Error handling. Always add exception blocks. Silent failures are worse than noisy ones. Log errors somewhere queryable.

Comments. Comment your code; especially for non-obvious logic or workarounds. Future you (or a teammate) will thank you.

Set-based operations over loops. Row-by-row processing inside a loop is often orders of magnitude slower than an equivalent INSERT … SELECT or MERGE. Reach for set-based SQL first.

Security. Use EXECUTE AS CALLER when the procedure should operate only on objects the caller has access to. Use EXECUTE AS OWNER when delegating specific, controlled tasks. Avoid EXECUTE IMMEDIATE with string concatenation from untrusted input.

Parameter handling. In Snowflake Scripting, parameters are read-only. Copy them to local variables before modifying.

Performance notes and optimization strategies

To optimize database operations and control resource consumption, it is essential to comprehend the performance characteristics of Snowflake stored procedures.

General performance notes

  • Stored procedures, especially those written in Snowpark languages (Python, Java, Scala), incur a small compilation and setup cost on their first call in a session. Subsequent calls often benefit from caching, reducing this overhead. JavaScript and Snowflake Scripting procedures generally have faster initial startup times compared to Snowpark.
  • Snowflake Scripting runs inside the SQL engine and adds little orchestration overhead for SQL-heavy flows. Use it when you mainly sequence SQL statements.
  • For Snowpark procedures, there can be a slight network latency due to the communication between the Snowpark client (where the UDF/procedure code might be prepared) and the Snowflake warehouse. However, Snowflake’s architecture minimizes this by executing the code directly on the virtual warehouse.

Language-Specific Performance Considerations

  • Snowflake Scripting (SQL):
    • Snowflake Scripting is designed to be very efficient for orchestrating SQL statements. Its native integration with Snowflake’s execution engine allows for minimal context switching.
    • While Snowflake Scripting supports loops, heavily transactional or large data operations performed row-by-row within loops can be significantly slower than equivalent set-based SQL operations. Prioritizing INSERT … SELECT, UPDATE … FROM and other set-based DML is always recommended for performance.
  • JavaScript:
    • Minimize the number of snowflake.execute() calls. Build multi-row or multi-step queries server-side and run them in one call. Do not call snowflake.execute() inside tight loops for thousands of rows.
    • Remember the API is synchronous. You do not get client-side asynchronous threads inside stored procedures. Keep the JS body focused on control flow, not row processing.
  • Snowpark (Python, Java, Scala):
    • avor DataFrame transformations that stay lazy. Only call materializing actions (collect(), to_pandas(), to_pandas_batches()) when the result set is small enough to fit memory. Use to_pandas_batches() for chunked materialization.
    • Use Snowpark for compute that is hard to express in SQL, for safe use of third-party libraries, or for machine learning where you need local Python tooling. But profile your code. Snowflake added a built-in profiler for Snowpark Python to find hotspots and CPU-bound parts. Use it.

Optimization Strategies

  • Favor set-based SQL. Rewrite row-by-row loops into set operations (INSERT ... SELECT, MERGE, UPDATE ... FROM) for large datasets.
  • Minimize cross-language context switches. For JavaScript or Snowpark, reduce the number of execute/statement calls by consolidating SQL or using table-driven processing.
  • Use temporary/staging tables for multi-step pipelines instead of passing large datasets back and forth between client code and SQL. Temporary tables let the engine reuse metadata and cache.
  • Be cautious with EXECUTE IMMEDIATE. Dynamic SQL is powerful but you lose some compile-time optimization opportunities. Use it only when necessary and ensure the generated SQL is optimized. For long-running dynamic flows, validate performance by examining the generated query plan.
  • Control and understand caching. Disable result cache for fair benchmarking with ALTER SESSION SET USE_CACHED_RESULT = FALSE; and re-enable afterwards. Remember result cache, metadata cache and warehouse cache are separate layers. Warehouse suspension can clear local caches.
  • Right-size compute. Increase warehouse size to get more disk/CPU per query. For concurrency spikes, use multi-cluster warehouses. Consider enabling Query Acceleration Service for workloads with long, I/O heavy queries. Monitor cost vs speed trade-offs.
  • Monitor and profile. Use Snowsight Query History, QUERY_HISTORY table functions and the query profile to see each statement the procedure runs and its breakdown. Each internal SQL executed by a stored procedure shows up in query history with associated metrics. Use those to find hotspots.
  • Batch I/O / Dataframe pushes. For Snowpark Python, prefer DataFrame transformations and write operations and avoid to_pandas() except on small datasets. For large transfers, to_pandas_batches() is the safer pattern.

Conclusion

And that’s a wrap! Snowflake stored procedures serve as a powerful tool, allowing users to seamlessly integrate procedural code that executes SQL. Beyond just being a sequence of SQL statements, these procedures offer a dynamic environment where branching and looping come to life through programmatic constructs. Their true strength lies in their reusability, ensuring that once a procedure is crafted, it can be invoked repeatedly, guaranteeing consistent and efficient operations every time.

In this article, we covered:

  • What stored procedures are and when to use them
  • The full syntax and supported languages
  • How caller’s rights and owner’s rights work
  • How to declare and use variables, cursors and RESULTSETs
  • Branching and looping constructs
  • Exception handling
  • EXECUTE IMMEDIATE for dynamic SQL
  • Step-by-step JavaScript stored procedure creation
  • Performance considerations and optimization strategies

… and so much more!

Want to learn more? Reach out for a chat

 

FAQs

What are Snowflake stored procedures?

Stored procedures in Snowflake are reusable, named database objects containing procedural logic and one or more SQL statements. They’re compiled at runtime on first call in a session; not pre-compiled like in some traditional relational databases.

Do Snowflake databases support stored procedures?

Yes. Snowflake supports creating and executing stored procedures.

Why use stored procedures in Snowflake?

They let you perform branching, looping and error handling inside Snowflake, automate repetitive multi-step operations and delegate controlled access to data without granting broad privileges.

Are there naming conventions for Snowflake stored procedures?

Snowflake doesn’t enforce a naming convention beyond requiring valid identifiers. That said, consistent, descriptive names make procedures easier to manage, especially since Snowflake supports overloading (same name, different argument types). Since stored procedures support overloading, the argument list is part of their full identity.

Can I write stored procedures in JavaScript within Snowflake?

Yes. Snowflake supports JavaScript as an inline handler language with its own API (snowflake.execute(), snowflake.createStatement(), etc.) for running SQL from within JavaScript code.

How do I create a stored procedure in Snowflake?

Use CREATE PROCEDURE to define it and CALL to execute it.

What’s the difference between stored procedures and UDFs in Snowflake?

Stored procedures support multiple SQL statements, DDL/DML operations, transactions and procedural logic, and they’re invoked with CALL. User-defined functions (UDFs) must return a value and are designed to be called inline within SQL expressions. UDFs only support SELECT-type logic; no DDL or DML.

Are there risks with nested calls or recursion in Snowflake stored procedures?

Yes. Snowflake’s current maximum stack depth for nested stored procedure calls is 16, including the top-level call. That limit can be lower if individual procedures in the chain consume significant resources. Design recursive or deeply nested procedures with care.

What languages are supported for writing stored procedures in Snowflake?

Snowflake supports Java, Python and Scala (via the Snowpark application programming interface, or API), Snowflake Scripting (SQL) and JavaScript.

How do I specify arguments when calling a stored procedure?

Arguments can be passed by name (arg_name => value) or by position. You must use one style consistently within a single CALL. Note that mixing the two isn’t allowed. Snowflake also supports default parameter values, so optional arguments can be omitted if a default is defined.

Is there a way to write anonymous procedures in Snowflake?

Yes. Snowflake supports anonymous procedures via CALL (WITH … CALL …). They don’t require CREATE PROCEDURE schema privileges and are discarded after execution—useful for one-off automation.

Can I return a table from a Snowflake stored procedure?

Yes, for Snowflake Scripting procedures. Use RETURNS TABLE (…) in the procedure definition and return data with RETURN TABLE(resultset_variable). JavaScript stored procedures return a single scalar value. If you need to surface tabular data from a JS procedure, one workaround is to populate a temporary table inside the procedure and query it separately after the call.