Snowflake Scripting UDFs

Snowflake 支持包含 Snowflake Scripting 过程语言的 SQL 用户定义函数 (UDFs)。这些 UDFs 被称为 Snowflake Scripting UDFs

Snowflake Scripting UDFs 可以在 SQL 语句中调用,例如 SELECT 语句或 INSERT 语句。因此,它们比 Snowflake Scripting 存储过程更灵活,后者只能通过 SQL CALL 命令调用。

一般用法

Snowflake Scripting UDF 会评估过程代码并返回标量值(即单个值)。

您可以在 Snowflake Scripting UDFs 中使用以下 Snowflake Scripting 语法子集:

支持的数据类型

Snowflake Scripting UDFs 支持输入参数和返回值的以下数据类型:

  • :doc:`/sql-reference/data-types-numeric`(例如 INTEGER、NUMBER 和 FLOAT)

  • :doc:`/sql-reference/data-types-text`(例如 VARCHAR 和 BINARY)

  • :doc:`/sql-reference/data-types-datetime`(例如 DATE、TIME 和 TIMESTAMP)

  • :doc:`/sql-reference/data-types-logical`(例如,BOOLEAN)

Snowflake Scripting UDFs 仅对输入参数支持以下数据类型:

  • :doc:`/sql-reference/data-types-semistructured`(例如 VARIANT、OBJECT 和 ARRAY)

  • :doc:`/sql-reference/data-types-structured`(例如 ARRAY、OBJECT 和 MAP)

限制

以下限制适用于 Snowflake Scripting UDFs:

  • 以下类型的 Snowflake Scripting 语法在 Snowflake Scripting UDFs 中不受支持:

  • SQL 语句在 Snowflake Scripting UDFs 中不受支持(包括 SELECT、INSERT、UPDATE 等等)。

  • Snowflake Scripting UDFs 不能被定义为表函数。

  • 以下表达式类型在 Snowflake Scripting UDFs 中不受支持:

    • 用户定义的函数

    • 聚合函数

    • 窗口函数

  • 在创建物化视图时,不能使用 Snowflake Scripting UDFs。

  • 在创建行访问策略和掩码策略时,不能使用 Snowflake Scripting UDFs。

  • Snowflake Scripting UDFs 不能用于指定列的默认值。

  • 在 COPY INTO 命令中进行数据加载和卸载时,不能使用 Snowflake Scripting UDFs。

  • Snowflake Scripting UDFs 不能是可记忆化的。

  • Snowflake Scripting UDFs 的输入参数数量限制为 500 个。

  • 您不能为 Snowflake Scripting UDFs 记录日志消息

示例

以下示例创建并调用 Snowflake Scripting UDFs:

创建一个带变量的 Snowflake Scripting UDF

创建一个根据两个参数的值计算利润的 Snowflake Scripting UDF:

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

备注

如果您在 :doc:` Python Connector </developer-guide/python-connector/python-connector>` 代码中使用 Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string 方法,本示例需要进行少量更改。有关更多信息,请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting

在查询中调用 calculate_profit

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

您可以使用相同的 Snowflake Scripting UDF 并为参数指定列。首先,创建表并插入数据:

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

在查询中调用 calculate_profit 并为参数指定列:

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

创建带条件逻辑的 Snowflake Scripting UDF

创建一个使用条件逻辑根据输入 INTEGER 值确定部门名称的 Snowflake Scripting UDF:

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

备注

如果您在 :doc:` Python Connector </developer-guide/python-connector/python-connector>` 代码中使用 Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string 方法,本示例需要进行少量更改。有关更多信息,请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting

在查询中调用 check_dept

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

在调用 Snowflake Scripting UDF 时,您可以在参数中使用 SQL 变量。以下示例设置一个 SQL 变量,然后在调用 check_dept UDF 时使用该变量:

SET my_variable = 3;

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

创建带循环的 Snowflake Scripting UDF

创建一个使用循环计算从 1 到参数提供的目标数字的所有数字之和的 Snowflake Scripting UDF:

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

备注

如果您在 :doc:` Python Connector </developer-guide/python-connector/python-connector>` 代码中使用 Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string 方法,本示例需要进行少量更改。有关更多信息,请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting

在查询中调用 count_to

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

创建带异常处理的 Snowflake Scripting UDF

创建一个声明异常并随后触发该异常的 Snowflake Scripting UDF:

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

备注

如果您在 :doc:` Python Connector </developer-guide/python-connector/python-connector>` 代码中使用 Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string 方法,本示例需要进行少量更改。有关更多信息,请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting

在查询中调用 raise_exception 并为输入值指定 1

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

在查询中调用 raise_exception 并为输入值指定 2

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

在查询中调用 raise_exception 并为输入值指定 NULL

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

创建一个返回用于 INSERT 语句的值的 Snowflake Scripting UDF

创建一个返回用于 INSERT 语句的值的 Snowflake Scripting UDF。创建要插入值的表:

CREATE OR REPLACE TABLE test_sql_udf_insert (num NUMBER);
Copy

创建一个返回数值的 SQL UDF:

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

备注

如果您在 :doc:` Python Connector </developer-guide/python-connector/python-connector>` 代码中使用 Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string 方法,本示例需要进行少量更改。有关更多信息,请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting

在多个 INSERT 语句中调用 value_to_insert

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

查询表以查看插入的值:

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

创建在 WHERE 和 ORDER BY 子句中调用的 Snowflake Scripting UDF

创建一个返回用于 WHERE 或 ORDER BY 子句的值的 Snowflake Scripting UDF。创建表并插入值:

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

创建一个返回两个输入值乘积的数值的 SQL UDF:

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

备注

如果您在 :doc:` Python Connector </developer-guide/python-connector/python-connector>` 代码中使用 Snowflake CLISnowSQLClassic Consoleexecute_streamexecute_string 方法,本示例需要进行少量更改。有关更多信息,请参阅 在 Snowflake CLI、SnowSQL、Classic Console 和 Python Connector 中使用 Snowflake Scripting

在查询的 WHERE 子句中调用 get_product 以返回乘积大于 350 的行:

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

在查询的 ORDER BY 子句中调用 get_product,按 UDF 返回的乘积从低到高排序结果:

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