CREATE FUNCTION

创建新的 UDF(用户定义函数)。该函数可以返回标量结果或表格结果,具体取决于您如何配置该函数。

创建 UDF 时,指定一个处理程序,该处理程序的代码是用支持的语言之一编写的。根据处理程序的语言,可以包含与 CREATE FUNCTION 语句内联的处理程序源代码,也可以从 CREATE FUNCTION 引用处理程序的位置,其中处理程序是预编译的,或者是暂存区上的源代码。

下表列出了每种支持的语言,以及其代码是否可以与 CREATE FUNCTION 保持内联或保留在暂存区上。有关更多信息,请参阅 将处理程序代码保持内联或保留在暂存区

语言

处理程序位置

Java

内联或暂存

JavaScript

内联

Python

内联或暂存

Scala

内联或暂存

SQL

内联

另请参阅:

ALTER FUNCTIONDROP FUNCTIONSHOW USER FUNCTIONSDESCRIBE FUNCTION

语法

CREATE FUNCTION 的语法因您使用的 UDF 处理程序语言而异。

Java 处理程序

如果源代码是内联的,请使用以下语法:

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE JAVA
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ { VOLATILE | IMMUTABLE } ]
  [ RUNTIME_VERSION = <java_jdk_version> ]
  [ COMMENT = '<string_literal>' ]
  [ IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] ) ]
  [ PACKAGES = ( '<package_name_and_version>' [ , ... ] ) ]
  HANDLER = '<path_to_method>'
  [ EXTERNAL_ACCESS_INTEGRATIONS = ( <name_of_integration> [ , ... ] ) ]
  [ SECRETS = ('<secret_variable_name>' = <secret_name> [ , ... ] ) ]
  [ TARGET_PATH = '<stage_path_and_file_name_to_write>' ]
  AS '<function_definition>'
Copy

如果要在暂存区上(例如在 JAR 中)引用处理程序代码,请使用以下语法:

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE JAVA
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ { VOLATILE | IMMUTABLE } ]
  [ RUNTIME_VERSION = <java_jdk_version> ]
  [ COMMENT = '<string_literal>' ]
  IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] )
  HANDLER = '<path_to_method>'
  [ EXTERNAL_ACCESS_INTEGRATIONS = ( <name_of_integration> [ , ... ] ) ]
  [ SECRETS = ('<secret_variable_name>' = <secret_name> [ , ... ] ) ]
Copy

JavaScript 处理程序

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE JAVASCRIPT
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ { VOLATILE | IMMUTABLE } ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'
Copy

Python 处理程序

如果源代码是内联的,请使用以下语法:

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] [ AGGREGATE ] FUNCTION [ IF NOT EXISTS ] <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE PYTHON
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ { VOLATILE | IMMUTABLE } ]
  RUNTIME_VERSION = <python_version>
  [ COMMENT = '<string_literal>' ]
  [ IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] ) ]
  [ PACKAGES = ( '<package_name>[==<version>]' [ , ... ] ) ]
  HANDLER = '<function_name>'
  [ EXTERNAL_ACCESS_INTEGRATIONS = ( <name_of_integration> [ , ... ] ) ]
  [ SECRETS = ('<secret_variable_name>' = <secret_name> [ , ... ] ) ]
  AS '<function_definition>'
Copy

如果将在暂存区(例如在模块中)引用处理程序代码,请使用以下语法:

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] [ AGGREGATE ] FUNCTION [ IF NOT EXISTS ] <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE PYTHON
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ { VOLATILE | IMMUTABLE } ]
  RUNTIME_VERSION = <python_version>
  [ COMMENT = '<string_literal>' ]
  IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] )
  [ PACKAGES = ( '<package_name>[==<version>]' [ , ... ] ) ]
  HANDLER = '<module_file_name>.<function_name>'
  [ EXTERNAL_ACCESS_INTEGRATIONS = ( <name_of_integration> [ , ... ] ) ]
  [ SECRETS = ('<secret_variable_name>' = <secret_name> [ , ... ] ) ]
Copy

Scala 处理程序

如果源代码是内联的,请使用以下语法:

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS <result_data_type>
  [ [ NOT ] NULL ]
  LANGUAGE SCALA
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ { VOLATILE | IMMUTABLE } ]
  [ RUNTIME_VERSION = <scala_version> ]
  [ COMMENT = '<string_literal>' ]
  [ IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] ) ]
  [ PACKAGES = ( '<package_name_and_version>' [ , ... ] ) ]
  HANDLER = '<path_to_method>'
  [ TARGET_PATH = '<stage_path_and_file_name_to_write>' ]
  AS '<function_definition>'
Copy

如果要在暂存区上(例如在 JAR 中)引用处理程序代码,请使用以下语法:

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION [ IF NOT EXISTS ] <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS <result_data_type>
  [ [ NOT ] NULL ]
  LANGUAGE SCALA
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ { VOLATILE | IMMUTABLE } ]
  [ RUNTIME_VERSION = <scala_version> ]
  [ COMMENT = '<string_literal>' ]
  IMPORTS = ( '<stage_path_and_file_name_to_read>' [ , ... ] )
  HANDLER = '<path_to_method>'
Copy

SQL 处理程序

CREATE [ OR REPLACE ] [ { TEMP | TEMPORARY } ] [ SECURE ] FUNCTION <name> (
    [ <arg_name> <arg_data_type> [ DEFAULT <default_value> ] ] [ , ... ] )
  [ COPY GRANTS ]
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  [ { VOLATILE | IMMUTABLE } ]
  [ MEMOIZABLE ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'
Copy

必填参数

所有语言

name ( [ arg_name arg_data_type [ DEFAULT default_value ] ] [ , ... ] )

指定 UDF 的标识符 (name)、任何输入实参以及任何可选实参的默认值。

RETURNS ...

指定 UDF 返回的结果,该结果决定 UDF 类型:

  • result_data_type:创建返回具有指定数据类型的单个值的标量 UDF。

    备注

    对于使用 Java、Python 或 Scala 编写的 UDF 处理程序,result_data_type 必须位于下表中与处理程序语言对应的 SQL Data Type 列中:

  • TABLE ( col_name col_data_type , ... ):创建一个表 UDF,用于返回带有指定表列和列类型的表格结果。

    备注

    对于 Scala UDFs,不支持 TABLE 返回类型。

AS function_definition

定义调用 UDF 时执行的处理程序代码。function_definition 值必须是使用处理程序支持的语言之一的源代码。代码可能包括:

有关更多详细信息,请参阅 `使用说明`_(本主题内容)。

备注

当在使用 IMPORTS 子句的暂存区上引用 UDF 处理程序代码时,不需要 AS 子句。

Java

LANGUAGE JAVA

指定代码使用 Java 语言。

RUNTIME_VERSION = java_jdk_version

指定要使用的 Java JDK 运行时版本。支持的 Java 版本包括:

  • 11.x

  • 17.x(所有账户都可以使用此功能的预览支持。)

如果未设置 RUNTIME_VERSION,则使用 Java JDK 11。

IMPORTS = ( 'stage_path_and_file_name_to_read' [ , ... ] )

要导入的文件的位置(暂存区)、路径和名称。

文件可以是 JAR 文件,也可以是其他类型的文件。

如果文件是 JAR 文件,则它可以包含一个或多个 .class 文件以及零个或多个资源文件。

不支持 JNI(Java 本地接口)。Snowflake 禁止加载包含原生代码(而不是 Java 字节码)的库。

Java UDFs 还可以读取非 JAR 文件。有关示例,请参阅 读取 IMPORTS 中静态指定的文件

如果计划将文件(JAR 文件或其他文件)复制到暂存区,则 Snowflake 建议使用命名的内部暂存区,因为 PUT 命令支持将文件复制到命名的内部暂存区,并且 PUT 命令通常是将 JAR 文件移到暂存区的最简单方法。

允许使用外部暂存区,但不受 PUT 支持。

IMPORTS 子句中的每个文件都必须具有唯一的名称,即使这些文件位于不同的子目录或不同的暂存区。

如果同时存在 IMPORTS 和 TARGET_PATH 子句,即使文件位于不同的子目录或不同的暂存区,TARGET_PATH 子句中的文件名也必须不同于 IMPORTS 子句中的每个文件名。

如果 TARGET_PATH 与现有文件匹配,则 Snowflake 将返回错误;您无法使用 TARGET_PATH 覆盖现有文件。

对于处理程序位于暂存区的 UDF,需要使用 IMPORTS 子句,因为该子句指定包含 UDF 的 JAR 文件的位置。

对于处理程序代码内联的 UDF,仅当内联 UDF 需要访问其他文件(例如库或文本文件)时,才需要 IMPORTS 子句。

对于 Snowflake 系统包(如 Snowpark 包),您可以使用 PACKAGES 子句指定包,而不是使用 IMPORTS 指定其 JAR 文件。执行此操作时,包 JAR 文件无需包含在 IMPORTS 值中。

内联 Java

AS function_definition

内联 Java UDFs 需要 函数定义

HANDLER = handler_name

处理程序方法或类的名称。

  • 如果处理程序用于标量 UDF,返回非表格值,则 HANDLER 值应为方法名称,格式如下:MyClass.myMethod

  • 如果处理程序用于表格 UDF,则 HANDLER 值应为处理程序类的名称。

JavaScript

LANGUAGE JAVASCRIPT

指定代码使用 JavaScript 语言。

Python

LANGUAGE PYTHON

指定代码使用 Python 语言。

RUNTIME_VERSION = python_version

指定要使用的 Python 版本。受支持的 Python 版本包括:

  • 3.8

  • 3.9

  • 3.10

  • 3.11

IMPORTS = ( 'stage_path_and_file_name_to_read' [ , ... ] )

要导入的文件的位置(暂存区)、路径和名称。

文件可以是 .py 文件,也可以是其他类型的文件。

Python UDFs 还可以读取非 Python 文件,例如文本文件。有关示例,请参阅 读取文件

如果计划将文件复制到暂存区,则 Snowflake 建议使用命名的内部暂存区,因为 PUT 命令支持将文件复制到命名的内部暂存区,并且 PUT 命令通常是将文件移到暂存区的最简单方法。

允许使用外部暂存区,但不受 PUT 支持。

IMPORTS 子句中的每个文件都必须具有唯一的名称,即使这些文件位于不同的子目录或不同的暂存区。

当处理程序代码存储在暂存区时,必须使用 IMPORTS 子句指定处理程序代码的位置。

对于内联 Python UDF,仅当 UDF 处理程序需要访问其他文件(如包或文本文件)时,才需要 IMPORTS 子句。

对于 Snowflake 系统中包含的包(如 ` numpy <https://numpy.org/doc/stable/ (https://numpy.org/doc/stable/)>`_),可以单独使用 PACKAGES 子句指定包,而不使用包的源作为 IMPORTS 值。

HANDLER = handler_name

处理程序函数或类的名称。

  • 如果处理程序用于标量 UDF,返回非表格值,则 HANDLER 值应为函数名称。如果处理程序代码与 CREATE FUNCTION 语句内联,则可以单独使用函数名称。在暂存区引用处理程序代码时,应使用模块名称限定此值,格式如下:my_module.my_function

  • 如果处理程序用于表格 UDF,则 HANDLER 值应为处理程序类的名称。

Scala

LANGUAGE SCALA

指定代码使用 Scala 语言。

RUNTIME_VERSION = scala_version

指定要使用的 Scala 运行时版本。支持的 Scala 版本包括:

  • 2.12

如果未设置 RUNTIME_VERSION,则使用 Scala 2.12。

IMPORTS = ( 'stage_path_and_file_name_to_read' [ , ... ] )

要导入的文件(如 JAR 文件或其他类型的文件)的位置(暂存区)、路径和名称。

  • JAR 文件可能包含处理程序依赖项库。该文件可以包含一个或多个 .class 文件以及零个或多个资源文件。

    不支持 JNI(Java 本地接口)。Snowflake 禁止加载包含原生代码(而不是 Java 字节码)的库。

  • 非 JAR 文件可能是处理程序代码读取的文件。有关示例,请参阅 读取 IMPORTS 中静态指定的文件

如果计划将文件复制到暂存区,则 Snowflake 建议使用命名的内部暂存区,因为 PUT 命令支持将文件复制到命名的内部暂存区,并且 PUT 命令通常是将 JAR 文件移到暂存区的最简单方法。允许使用外部暂存区,但不受 PUT 支持。

IMPORTS 子句中的每个文件都必须具有唯一的名称,即使这些文件位于不同的暂存区子目录或不同的暂存区。

如果同时存在 IMPORTS 和 TARGET_PATH 子句,即使文件位于不同的暂存区子目录或不同的暂存区,TARGET_PATH 子句中的文件名也必须不同于 IMPORTS 子句中列出的任何文件的文件名。

对于处理程序位于暂存区的 UDF,需要使用 IMPORTS 子句,因为该子句指定包含 UDF 的 JAR 文件的位置。

对于处理程序代码内联的 UDF,仅当内联 UDF 需要访问其他文件(例如库或文本文件)时,才需要 IMPORTS 子句。

对于 Snowflake 系统包(如 Snowpark 包),您可以使用 PACKAGES 子句指定包,而不是使用 IMPORTS 指定其 JAR 文件。执行此操作时,包 JAR 文件无需包含在 IMPORTS 值中。

内联 Scala

AS function_definition

使用内联 Scala 处理程序代码的 UDFs 需要 :ref:` 函数定义 <label-create_udf_function_definition>`。

HANDLER = handler_name

处理程序方法或类的名称。

  • 如果处理程序用于标量 UDF,返回非表格值,则 HANDLER 值应为方法名称,格式如下:MyClass.myMethod

可选参数

所有语言

SECURE

指定函数为安全函数。有关安全函数的更多信息,请参阅 使用安全 UDFs 和存储过程保护敏感信息

{ TEMP | TEMPORARY }

指定函数仅在创建该函数的 会话 期间持续存在。在会话结束时会删除临时函数。

默认:无值。如果函数未声明为 TEMPORARY,则该函数是永久函数。

不能创建与架构中已存在的函数同名的临时 用户定义函数

[ [ NOT ] NULL ]

指定函数是可以返回 NULL 值,还是只能返回 NON-NULL 值。默认值为 NULL(即函数可以返回 NULL)。

备注

目前,SQL UDFs 不强制使用 NOT NULL 子句。声明为 NOT NULL 的 SQL UDFs 可以返回 NULL 值。Snowflake 建议避免对 SQL UDFs 使用 NOT NULL,除非编写函数中的代码以确保永远不会返回 NULL 值。

CALLED ON NULL INPUT . { RETURNS NULL ON NULL INPUT | STRICT }

指定使用 null 输入调用 UDF 时的行为。与系统定义的函数(当任何输入为 null 时总是返回 null)相反,UDFs 可以处理 null 输入,即使输入为 null 也返回非 null 值:

  • CALLED ON NULL INPUT 将始终使用 null 输入调用 UDF。这取决于 UDF 是否适当地处理这些值。

  • 如果任何输入为 null,则 RETURNS NULL ON NULL INPUT (或其同义词 STRICT)将不会调用 UDF。相反,将始终为该行返回 null 值。请注意,对于非 null 输入,UDF 可能仍返回 null 值。

备注

SQL UDFs 不支持 RETURNS NULL ON NULL INPUT (STRICT)。SQL UDFs 实际上使用 CALLED ON NULL INPUT。在 SQL UDFs 中,必须处理 null 输入值。

默认:CALLED ON NULL INPUT

{ VOLATILE | IMMUTABLE }

指定在返回结果时 UDF 的行为:

  • VOLATILE:UDF 可以为不同的行返回不同的值,即使是相同的输入也如此(例如,由于非确定性和有状态性)。

  • IMMUTABLE:UDF 假定当使用相同的输入调用该函数时,该函数将始终返回相同的结果。此保证未经检查。为相同输入返回不同值的 UDF 指定 IMMUTABLE,这样会导致未定义的行为。

默认:VOLATILE

备注

在聚合函数上,当使用 AGGREGATE 参数时,不支持 IMMUTABLE。因此,所有聚合函数默认都是 VOLATILE。

COMMENT = 'string_literal'

指定 UDF 的注释,该注释在 SHOW FUNCTIONSSHOW USER FUNCTIONS 输出的 DESCRIPTION 列中显示。

默认:user-defined function

COPY GRANTS

指定在使用 CREATE OR REPLACE FUNCTION 创建新函数时保留原始函数的访问权限。

该参数将现有函数中的所有权限(OWNERSHIP 除外)复制到新函数中。新函数将继承架构中为该对象类型定义的任何未来授权。默认情况下,执行 CREATE FUNCTION 语句的角色拥有新函数。

注意:

  • 通过 数据共享,如果现有函数已共享到另一个账户,则替换函数也会共享。

  • 替换函数的 SHOW GRANTS 输出会将复制权限的获得者列为执行 CREATE FUNCTION 语句的角色,并附带执行语句时的当前时间戳。

  • 复制授权的操作在 CREATE FUNCTION 命令中会以原子方式发生(即在同一事务中)。

Java

PACKAGES = ( 'package_name_and_version' [ , ... ] )

作为依赖项所需的 Snowflake 系统包的名称和版本号。该值的格式应为 package_name:version_number,其中 package_namesnowflake_domain:package。请注意,您可以将 latest 指定为版本号,以便让 Snowflake 使用系统上提供的最新版本。

例如:

-- Use version 1.2.0 of the Snowpark package.
PACKAGES=('com.snowflake:snowpark:1.2.0')

-- Use the latest version of the Snowpark package.
PACKAGES=('com.snowflake:snowpark:latest')
Copy

您可以通过在 Snowflake 中执行以下 SQL 来发现支持的系统包列表:

SELECT * FROM INFORMATION_SCHEMA.PACKAGES WHERE LANGUAGE = 'java';
Copy

对于使用 PACKAGES 指定的依赖项,不需要在 IMPORTS 子句中指定其 JAR 文件。

内联 Java

TARGET_PATH = stage_path_and_file_name_to_write

TARGET_PATH 子句指定在编译 function_definition 中指定的源代码后,Snowflake 应将编译后的代码(JAR 文件)写入的位置。

如果包含此子句,则用户应在不再需要 JAR 文件时(通常是在删除 Java UDF 时)手动移除该文件。

如果省略此子句,则每次需要代码时,Snowflake 都会重新编译源代码。JAR 文件不会永久存储,用户不需要清理 JAR 文件。

如果 TARGET_PATH 与现有文件匹配,则 Snowflake 将返回错误;您无法使用 TARGET_PATH 覆盖现有文件。

EXTERNAL_ACCESS_INTEGRATIONS = ( integration_name [ , ... ] )

此函数的处理程序代码访问外部网络所需的 :doc:` 外部访问集成 </sql-reference/sql/create-external-access-integration>` 的名称。

外部访问集成指定 网络规则密钥,这些规则和密钥指定了处理程序代码在请求外部网络(如外部 REST API)时可以使用的外部位置和凭据(如果有)。

SECRETS = ( 'secret_variable_name' = secret_name [ , ...  ] )

将密钥的名称分配给变量,以便在从处理程序代码中的密钥中检索信息时,可以使用这些变量引用密钥。

对于您在此处指定的密钥,其必须获得指定为此 CREATE FUNCTION 命令的 EXTERNAL_ACCESS_INTEGRATIONS 参数值的 外部访问集成 的允许。

此参数的值是以逗号分隔的赋值表达式列表,其中包含以下部分:

  • secret_name,即允许使用的密钥的名称。

    如果指定的 SECRETS 值的密钥未包含在由 EXTERNAL_ACCESS_INTEGRATIONS 参数指定的集成中,将收到错误消息。

  • 'secret_variable_name' 作为从密钥中检索信息时将在处理程序代码中使用的变量。

有关更多信息(包括示例),请参阅 在函数或过程中使用外部访问集成

Python

AGGREGATE

指定函数是聚合函数。有关用户定义聚合函数的更多信息,请参阅 Python 用户定义的聚合函数

备注

在聚合函数上,当使用 AGGREGATE 参数时,不支持 IMMUTABLE。因此,所有聚合函数默认都是 VOLATILE。

PACKAGES = ( 'package_name_and_version' [ , ... ] )

作为依赖项所需的包的名称和版本号。该值的格式应为 package_name==version_number。如果省略版本号,Snowflake 将使用系统上提供的最新包。

例如:

-- Use version 1.2.2 of the NumPy package.
PACKAGES=('numpy==1.2.2')

-- Use the latest version of the NumPy package.
PACKAGES=('numpy')
Copy

您可以通过在 Snowflake 中执行以下 SQL 来发现支持的系统包列表:

SELECT * FROM INFORMATION_SCHEMA.PACKAGES WHERE LANGUAGE = 'python';
Copy

有关包含的包的更多信息,请参阅 使用第三方包

EXTERNAL_ACCESS_INTEGRATIONS = ( integration_name [ , ... ] )

此函数的处理程序代码访问外部网络所需的 :doc:` 外部访问集成 </sql-reference/sql/create-external-access-integration>` 的名称。

外部访问集成指定 网络规则密钥,这些规则和密钥指定了处理程序代码在请求外部网络(如外部 REST API)时可以使用的外部位置和凭据(如果有)。

SECRETS = ( 'secret_variable_name' = secret_name [ , ...  ] )

将密钥的名称分配给变量,以便在从处理程序代码中的密钥中检索信息时,可以使用这些变量引用密钥。

对于您在此处指定的密钥,其必须获得指定为此 CREATE FUNCTION 命令的 EXTERNAL_ACCESS_INTEGRATIONS 参数值的 外部访问集成 的允许。

此参数的值是以逗号分隔的赋值表达式列表,其中包含以下部分:

  • secret_name,即允许使用的密钥的名称。

    如果指定的 SECRETS 值的密钥未包含在由 EXTERNAL_ACCESS_INTEGRATIONS 参数指定的集成中,将收到错误消息。

  • 'secret_variable_name' 作为从密钥中检索信息时将在处理程序代码中使用的变量。

有关更多信息(包括示例),请参阅 在函数或过程中使用外部访问集成

SQL

MEMOIZABLE

指定函数为可记忆的函数。

有关详细信息,请参阅 可记忆的 UDFs

Scala

PACKAGES = ( 'package_name_and_version' [ , ... ] )

作为依赖项所需的 Snowflake 系统包的名称和版本号。该值的格式应为 package_name:version_number,其中 package_namesnowflake_domain:package。请注意,您可以将 latest 指定为版本号,以便让 Snowflake 使用系统上提供的最新版本。

例如:

-- Use version 1.7.0 of the Snowpark package.
PACKAGES=('com.snowflake:snowpark:1.7.0')

-- Use the latest version of the Snowpark package.
PACKAGES=('com.snowflake:snowpark:latest')
Copy

您可以通过在 Snowflake 中执行以下 SQL 来发现支持的系统包列表:

SELECT * FROM INFORMATION_SCHEMA.PACKAGES WHERE LANGUAGE = 'scala';
Copy

对于使用 PACKAGES 指定的依赖项,不需要在 IMPORTS 子句中指定其 JAR 文件。

内联 Scala

TARGET_PATH = stage_path_and_file_name_to_write

TARGET_PATH 子句指定在编译 function_definition 中指定的源代码后,Snowflake 应将编译后的代码(JAR 文件)写入的位置。

如果包含此子句,您应在不再需要 JAR 文件时(通常是在删除 UDF 时)手动移除该文件。

如果省略此子句,则每次需要代码时,Snowflake 都会重新编译源代码。JAR 文件不会永久存储,您不需要清理 JAR 文件。

如果 TARGET_PATH 与现有文件匹配,则 Snowflake 将返回错误;您无法使用 TARGET_PATH 覆盖现有文件。

访问控制要求

用于执行此 SQL 命令的 角色 必须至少具有以下 权限

权限

对象

备注

CREATE FUNCTION

架构

USAGE

函数

通过向角色授予对新创建函数的 USAGE 权限,具有该角色的用户可以在 Snowflake 中的其他位置调用该函数(例如,External Tokenization 的掩码策略所有者角色)。

USAGE

外部访问集成

对于由 EXTERNAL_ACCESS_INTEGRATIONS 参数指定的集成(如果有)来说是必需的。有关更多信息,请参阅 CREATE EXTERNAL ACCESS INTEGRATION

READ

密钥

对于由 SECRETS 参数指定的密钥(如果有)来说是必需的。有关更多信息,请参阅 创建表示凭据的密钥在函数或过程中使用外部访问集成

USAGE

架构

对于包含由 SECRETS 参数指定的密钥(如果有)的架构来说是必需的。有关更多信息,请参阅 创建表示凭据的密钥在函数或过程中使用外部访问集成

请注意,对架构中的对象进行操作还需要对父数据库和架构具有 USAGE 权限。

有关创建具有指定权限集的自定义角色的说明,请参阅 创建自定义角色

有关对 安全对象 执行 SQL 操作的相应角色和权限授予的一般信息,请参阅 访问控制概述

使用说明

所有语言

  • function_definition 有大小限制。最大允许大小可能会发生变化。

  • 周围的 function_definition 分隔符可以是单引号或一对美元符号。

    使用 $$ 作为分隔符可以更轻松地编写包含单引号的函数。

    如果函数主体的分隔符是单引号字符,则 function_definition 中的任何单引号(例如字符串字面量) :emph:` 必须 ` 用单引号转义。

  • 如果在 :doc:` 掩码策略 <create-masking-policy>` 中使用 UDF,请确保列的数据类型、UDF 和掩码策略匹配。有关更多信息,请参阅 掩码策略中的用户定义函数

  • 如果在 UDF 的处理程序代码中指定 CURRENT_DATABASECURRENT_SCHEMA 函数,该函数会返回包含 UDF 的数据库或架构,而不是会话中使用的数据库或架构。

  • 关于元数据:

    注意

    客户应确保在使用 Snowflake 服务时,不会将个人数据(用户对象除外)、敏感数据、出口管制数据或其他受监管数据作为元数据输入。有关更多信息,请参阅 Snowflake 中的元数据字段

  • CREATE OR REPLACE <object> 语句是原子的。也就是说,当对象被替换时,旧对象将被删除,新对象将在单个事务中创建。

Java

  • 在 Java 中,原始数据类型不允许 NULL 值,因此为此类类型的实参传递 NULL 会导致错误。

  • 在 HANDLER 子句中,方法名称区分大小写。

  • 在 IMPORTS 和 TARGET_PATH 子句中:

    • 包、类和文件名 区分大小写

    • 暂存区名称 不区分大小写

  • 您可以使用 PACKAGES 子句指定 Snowflake 系统定义的依赖项(例如来自 Snowpark 的依赖项)的包名称和版本号。对于其他依赖项,请使用 IMPORTS 子句指定依赖项 JAR 文件。

  • Snowflake 验证:

    • CREATE FUNCTION 语句的 HANDLER 中指定的 JAR 文件存在并且包含指定的类和方法。

    • UDF 声明中指定的输入和输出类型与 Java 方法的输入和输出类型兼容。

    可以在创建时或执行时进行验证。

    • 如果用户在执行 CREATE FUNCTION 语句时连接到活动的 Snowflake 仓库,则 UDF 将在创建时进行验证。

    • 否则,将创建 UDF,但不会立即进行验证,并且 Snowflake 返回以下消息:Function <name> created successfully, but could not be validated since there is no active warehouse

JavaScript

  • Snowflake 在创建 UDF 时不会验证 JavaScript 代码(即,无论代码是否有效,都会成功创建 UDF)。如果代码无效,则在查询时调用 UDF 时将返回错误。

Python

  • 在 HANDLER 子句中,处理程序函数名称区分大小写。

  • 在 IMPORTS 子句中:

    • 文件名 区分大小写

    • 暂存区名称 不区分大小写

  • 您可以使用 PACKAGES 子句指定依赖项(例如来自 Snowpark 的依赖项)的包名称和版本号。对于其他依赖项,请使用 IMPORTS 子句指定依赖项文件。

  • Snowflake 验证:

    • CREATE FUNCTION 语句的 HANDLER 中指定的函数或类存在。

    • UDF 声明中指定的输入和输出类型与处理程序的输入和输出类型兼容。

Scala

  • 在 HANDLER 子句中,方法名称区分大小写。

  • 在 IMPORTS 和 TARGET_PATH 子句中:

    • 包、类和文件名 区分大小写

    • 暂存区名称 不区分大小写

  • 您可以使用 PACKAGES 子句指定 Snowflake 系统定义的依赖项(例如来自 Snowpark 的依赖项)的包名称和版本号。对于其他依赖项,请使用 IMPORTS 子句指定依赖项 JAR 文件。

  • Snowflake 验证:

    • CREATE FUNCTION 语句的 HANDLER 中指定的 JAR 文件存在并且包含指定的类和方法。

    • UDF 声明中指定的输入和输出类型与 Scala 方法的输入和输出类型兼容。

    可以在创建时或执行时进行验证。

    • 如果用户在执行 CREATE FUNCTION 语句时连接到活动的 Snowflake 仓库,则 UDF 将在创建时进行验证。

    • 否则,将创建 UDF,但不会立即进行验证,并且 Snowflake 返回以下消息:Function <name> created successfully, but could not be validated since there is no active warehouse

SQL

  • 目前,SQL UDFs 不强制使用 NOT NULL 子句。

示例

Java

以下是使用内联处理程序的 CREATE FUNCTION 基本示例:

create or replace function echo_varchar(x varchar)
returns varchar
language java
called on null input
handler='TestFunc.echoVarchar'
target_path='@~/testfunc.jar'
as
'class TestFunc {
  public static String echoVarchar(String x) {
    return x;
  }
}';
Copy

以下是 CREATE FUNCTION 的基本示例,其中引用了暂存处理程序:

create function my_decrement_udf(i numeric(9, 0))
    returns numeric
    language java
    imports = ('@~/my_decrement_udf_package_dir/my_decrement_udf_jar.jar')
    handler = 'my_decrement_udf_package.my_decrement_udf_class.my_decrement_udf_method'
    ;
Copy

有关 Java UDFs 的更多示例,请参阅 示例

JavaScript

创建一个名为 js_factorial 的 JavaScript UDF:

CREATE OR REPLACE FUNCTION js_factorial(d double)
  RETURNS double
  LANGUAGE JAVASCRIPT
  STRICT
  AS '
  if (D <= 0) {
    return 1;
  } else {
    var result = 1;
    for (var i = 2; i <= D; i++) {
      result = result * i;
    }
    return result;
  }
  ';
Copy

Python

以下示例中的代码创建一个 py_udf 函数,其处理程序代码内联为 udf

CREATE OR REPLACE FUNCTION py_udf()
  RETURNS VARIANT
  LANGUAGE PYTHON
  RUNTIME_VERSION = '3.8'
  PACKAGES = ('numpy','pandas','xgboost==1.5.0')
  HANDLER = 'udf'
AS $$
import numpy as np
import pandas as pd
import xgboost as xgb
def udf():
    return [np.__version__, pd.__version__, xgb.__version__]
$$;
Copy

以下示例中的代码创建一个 dream 函数,其处理程序位于 @my_stage 暂存区的 sleepy.py 文件中。

CREATE OR REPLACE FUNCTION dream(i int)
  RETURNS VARIANT
  LANGUAGE PYTHON
  RUNTIME_VERSION = '3.8'
  HANDLER = 'sleepy.snore'
  IMPORTS = ('@my_stage/sleepy.py')
Copy

Scala

以下是使用内联处理程序的 CREATE FUNCTION 基本示例:

CREATE OR REPLACE FUNCTION echo_varchar(x VARCHAR)
  RETURNS VARCHAR
  LANGUAGE SCALA
  RUNTIME_VERSION = 2.12
  HANDLER='Echo.echoVarchar'
  AS
  $$
  class Echo {
    def echoVarchar(x : String): String = {
      return x
    }
  }
  $$;
Copy

以下是 CREATE FUNCTION 的基本示例,其中引用了暂存处理程序:

CREATE OR REPLACE FUNCTION echo_varchar(x VARCHAR)
  RETURNS VARCHAR
  LANGUAGE SCALA
  RUNTIME_VERSION = 2.12
  IMPORTS = ('@udf_libs/echohandler.jar')
  HANDLER='Echo.echoVarchar';
Copy

有关 Scala UDFs 的更多示例,请参阅 Scala UDF 处理程序示例

SQL

创建一个简单的 SQL 标量 UDF,它返回数学常量 pi 的硬编码近似值:

CREATE FUNCTION pi_udf()
  RETURNS FLOAT
  AS '3.141592654::FLOAT'
  ;
Copy

创建一个返回硬编码值的简单 SQL 表 UDF:

CREATE FUNCTION simple_table_function ()
  RETURNS TABLE (x INTEGER, y INTEGER)
  AS
  $$
    SELECT 1, 2
    UNION ALL
    SELECT 3, 4
  $$
  ;
Copy
SELECT * FROM TABLE(simple_table_function());
Copy

输出:

SELECT * FROM TABLE(simple_table_function());
+---+---+
| X | Y |
|---+---|
| 1 | 2 |
| 3 | 4 |
+---+---+
Copy

创建一个接受多个参数的 UDF:

CREATE FUNCTION multiply1 (a number, b number)
  RETURNS number
  COMMENT='multiply two numbers'
  AS 'a * b';
Copy

创建一个名为 get_countries_for_user 的 SQL 表 UDF,用于返回查询结果:

CREATE OR REPLACE FUNCTION get_countries_for_user ( id NUMBER )
  RETURNS TABLE (country_code CHAR, country_name VARCHAR)
  AS 'SELECT DISTINCT c.country_code, c.country_name
      FROM user_addresses a, countries c
      WHERE a.user_id = id
      AND c.country_code = a.country_code';
Copy
语言: 中文