Snowflake Scripting UDFs

Snowflake supports SQL user-defined functions (UDFs) that contain Snowflake Scripting procedural language. These UDFs are called Snowflake Scripting UDFs.

Snowflake Scripting UDFs can be called in a SQL statement, such as a SELECT statement or INSERT statement. Therefore, they are more flexible than a Snowflake Scripting stored procedure, which can only be called in a SQL CALL command.

General usage

A Snowflake Scripting UDF evaluates procedural code and returns a scalar (that is, single) value.

You can use the following subset of Snowflake Scripting syntax in Snowflake Scripting UDFs:

Supported data types

Snowflake Scripting UDFs support the following data types for both input arguments and return values:

Snowflake Scripting UDFs support the following data types for input arguments only:

Limitations

The following limitations apply to Snowflake Scripting UDFs:

  • The following types of Snowflake Scripting syntax aren’t supported in Snowflake Scripting UDFs:

  • SQL statements aren’t supported in Snowflake Scripting UDFs (including SELECT, INSERT, UPDATE, and so on).

  • Snowflake Scripting UDFs can’t be defined as table functions.

  • The following expression types aren’t supported in Snowflake Scripting UDFs:

    • User-defined functions

    • Aggregation functions

    • Window functions

  • Snowflake Scripting UDFs can’t be used when creating a materialized view.

  • Snowflake Scripting UDFs can’t be used when creating row access policies and masking policies.

  • Snowflake Scripting UDFs can’t be used to specify a default column value.

  • Snowflake Scripting UDFs can’t be used in a COPY INTO command for data loading and unloading.

  • Snowflake Scripting UDFs can’t be memoizable.

  • Snowflake Scripting UDFs have a limit of 500 input arguments.

  • You can’t log messages for Snowflake Scripting UDFs.

Examples

The following examples create and call Snowflake Scripting UDFs:

Create a Snowflake Scripting UDF with variables

Create a Snowflake Scripting UDF that calculates profit based on the values of two arguments:

CREATE OR REPLACE FUNCTION calculate_profit(
  cost NUMBER(38, 2),
  revenue NUMBER(38, 2))
RETURNS number(38, 2)
LANGUAGE SQL
AS
DECLARE
  profit NUMBER(38, 2) DEFAULT 0.0;
BEGIN
  profit := revenue - cost;
  RETURN profit;
END;
Copy

Note

If you use Snowflake CLI, SnowSQL, the Classic Console, or the execute_stream or execute_string method in Python Connector code, this example requires minor changes. For more information, see Using Snowflake Scripting in Snowflake CLI, SnowSQL, the Classic Console, and Python Connector.

Call calculate_profit in a query:

SELECT calculate_profit(100, 110);
Copy
+----------------------------+
| CALCULATE_PROFIT(100, 110) |
|----------------------------|
|                      10.00 |
+----------------------------+

You can use the same Snowflake Scripting UDF and specify columns for the arguments. First, create a table and insert data:

CREATE OR REPLACE TABLE snowflake_scripting_udf_profit(
  cost NUMBER(38, 2),
  revenue NUMBER(38, 2));

INSERT INTO snowflake_scripting_udf_profit VALUES
  (100, 200),
  (200, 190),
  (300, 500),
  (400, 401);
Copy

Call calculate_profit in a query and specify the columns for the arguments:

SELECT calculate_profit(cost, revenue)
  FROM snowflake_scripting_udf_profit;
Copy
+---------------------------------+
| CALCULATE_PROFIT(COST, REVENUE) |
|---------------------------------|
|                          100.00 |
|                          -10.00 |
|                          200.00 |
|                            1.00 |
+---------------------------------+

Create a Snowflake Scripting UDF with conditional logic

Create a Snowflake Scripting UDF that uses conditional logic to determine the department name based on an input INTEGER value:

CREATE OR REPLACE function check_dept(department_id INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
AS
BEGIN
  IF (department_id < 3) THEN
    RETURN 'Engineering';
  ELSEIF (department_id = 3) THEN
    RETURN 'Tool Design';
  ELSE
    RETURN 'Marketing';
  END IF;
END;
Copy

Note

If you use Snowflake CLI, SnowSQL, the Classic Console, or the execute_stream or execute_string method in Python Connector code, this example requires minor changes. For more information, see Using Snowflake Scripting in Snowflake CLI, SnowSQL, the Classic Console, and Python Connector.

Call check_dept in a query:

SELECT check_dept(2);
Copy
+---------------+
| CHECK_DEPT(2) |
|---------------|
| Engineering   |
+---------------+

You can use a SQL variable in an argument when you call a Snowflake Scripting UDF. The following example sets a SQL variable and then uses the variable in a call to the check_dept UDF:

SET my_variable = 3;

SELECT check_dept($my_variable);
Copy
+--------------------------+
| CHECK_DEPT($MY_VARIABLE) |
|--------------------------|
| Tool Design              |
+--------------------------+

Create a Snowflake Scripting UDF with a loop

Create a Snowflake Scripting UDF that uses a loop to count all numbers up to a target number provided in an argument and calculate the sum of all of the numbers counted:

CREATE OR REPLACE function count_to(
  target_number INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
AS
DECLARE
  counter INTEGER DEFAULT 0;
  sum_total INTEGER DEFAULT 0;
BEGIN
  WHILE (counter < target_number) DO
    counter := counter + 1;
    sum_total := sum_total + counter;
  END WHILE;
  RETURN 'Counted to ' || counter || '. Sum of all numbers: ' || sum_total;
END;
Copy

Note

If you use Snowflake CLI, SnowSQL, the Classic Console, or the execute_stream or execute_string method in Python Connector code, this example requires minor changes. For more information, see Using Snowflake Scripting in Snowflake CLI, SnowSQL, the Classic Console, and Python Connector.

Call count_to in a query:

SELECT count_to(10);
Copy
+---------------------------------------+
| COUNT_TO(10)                          |
|---------------------------------------|
| Counted to 10. Sum of all numbers: 55 |
+---------------------------------------+

Create a Snowflake Scripting UDF with exception handling

Create a Snowflake Scripting UDF that declares an exception and then raises the exception:

CREATE OR REPLACE FUNCTION raise_exception(input_value INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
AS
DECLARE
  counter_val INTEGER DEFAULT 0;
  my_exception EXCEPTION (-20002, 'My exception text');
BEGIN
  WHILE (counter_val < 12) DO
    counter_val := counter_val + 1;
    IF (counter_val > 10) THEN
      RAISE my_exception;
    END IF;
  END WHILE;
  RETURN counter_val;
EXCEPTION
  WHEN my_exception THEN
    IF (input_value = 1) THEN
      RETURN 'My exception caught: ' || sqlcode;
    ELSEIF (input_value = 2) THEN
      RETURN 'My exception caught with different path: ' || sqlcode;
    END IF;
    RETURN 'Default exception handling path: ' || sqlcode;
END;
Copy

Note

If you use Snowflake CLI, SnowSQL, the Classic Console, or the execute_stream or execute_string method in Python Connector code, this example requires minor changes. For more information, see Using Snowflake Scripting in Snowflake CLI, SnowSQL, the Classic Console, and Python Connector.

Call raise_exception in a query and specify 1 for the input value:

SELECT raise_exception(1);
Copy
+-----------------------------+
| RAISE_EXCEPTION(1)          |
|-----------------------------|
| My exception caught: -20002 |
+-----------------------------+

Call raise_exception in a query and specify 2 for the input value:

SELECT raise_exception(2);
Copy
+-------------------------------------------------+
| RAISE_EXCEPTION(2)                              |
|-------------------------------------------------|
| My exception caught with different path: -20002 |
+-------------------------------------------------+t

Call raise_exception in a query and specify NULL for the input value:

SELECT raise_exception(NULL);
Copy
+-----------------------------------------+
| RAISE_EXCEPTION(NULL)                   |
|-----------------------------------------|
| Default exception handling path: -20002 |
+-----------------------------------------+

Create a Snowflake Scripting UDF that returns a value for an INSERT statement

Create a Snowflake Scripting UDF that returns a value that is used in an INSERT statement. Create the table that the values will be inserted into:

CREATE OR REPLACE TABLE test_sql_udf_insert (num NUMBER);
Copy

Create a SQL UDF that returns a numeric value:

CREATE OR REPLACE FUNCTION value_to_insert(l NUMBER, r NUMBER)
RETURNS number
LANGUAGE SQL
AS
BEGIN
  IF (r < 0) THEN
    RETURN l/r * -1;
  ELSEIF (r > 0) THEN
    RETURN l/r;
  ELSE
    RETURN 0;
END IF;
END;
Copy

Note

If you use Snowflake CLI, SnowSQL, the Classic Console, or the execute_stream or execute_string method in Python Connector code, this example requires minor changes. For more information, see Using Snowflake Scripting in Snowflake CLI, SnowSQL, the Classic Console, and Python Connector.

Call value_to_insert in multiple INSERT statements:

INSERT INTO test_sql_udf_insert SELECT value_to_insert(10, 2);
INSERT INTO test_sql_udf_insert SELECT value_to_insert(10, -2);
INSERT INTO test_sql_udf_insert SELECT value_to_insert(10, 0);
Copy

Query the table to view the inserted values:

SELECT * FROM test_sql_udf_insert;
Copy
+-----+
| NUM |
|-----|
|   5 |
|   5 |
|   0 |
+-----+

Create a Snowflake Scripting UDF called in WHERE and ORDER BY clauses

Create a Snowflake Scripting UDF that returns a value that is used in a WHERE or ORDER BY clause. Create a table and insert values:

CREATE OR REPLACE TABLE test_sql_udf_clauses (p1 INT, p2 INT);

INSERT INTO test_sql_udf_clauses VALUES
  (100, 7),
  (100, 3),
  (100, 4),
  (NULL, NULL);
Copy

Create a SQL UDF that returns a numeric value that is the product of the multiplication of two input values:

CREATE OR REPLACE FUNCTION get_product(a INTEGER, b INTEGER)
RETURNS VARCHAR
LANGUAGE SQL
AS
BEGIN
  RETURN a * b;
END;
Copy

Note

If you use Snowflake CLI, SnowSQL, the Classic Console, or the execute_stream or execute_string method in Python Connector code, this example requires minor changes. For more information, see Using Snowflake Scripting in Snowflake CLI, SnowSQL, the Classic Console, and Python Connector.

Call get_product in the WHERE clause of a query to return the rows where the product is greater than 350:

SELECT *
  FROM test_sql_udf_clauses
  WHERE get_product(p1, p2) > 350;
Copy
+-----+----+
|  P1 | P2 |
|-----+----|
| 100 |  7 |
| 100 |  4 |
+-----+----+

Call get_product in the ORDER BY clause of a query to order the results from the lowest to the highest product returned by the UDF:

SELECT *
  FROM test_sql_udf_clauses
  ORDER BY get_product(p1, p2);
Copy
+------+------+
|  P1  | P2   |
|------+------|
| 100  | 3    |
| 100  | 4    |
| 100  | 7    |
| NULL | NULL |
+------+------+
Language: English