CREATE FUNCTION¶
创建新的 UDF(用户定义函数)。该函数可以返回标量结果或表格结果,具体取决于您如何配置该函数。
创建 UDF 时,指定一个处理程序,该处理程序的代码是用支持的语言之一编写的。根据处理程序的语言,可以包含与 CREATE FUNCTION 语句内联的处理程序源代码,也可以从 CREATE FUNCTION 引用处理程序的位置,其中处理程序是预编译的,或者是暂存区上的源代码。
下表列出了每种支持的语言,以及其代码是否可以与 CREATE 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>'
如果要在暂存区上(例如在 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> [ , ... ] ) ]
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>'
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>'
如果将在暂存区(例如在模块中)引用处理程序代码,请使用以下语法:
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> [ , ... ] ) ]
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>'
如果要在暂存区上(例如在 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>'
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>'
必填参数¶
所有语言¶
name ( [ arg_name arg_data_type [ DEFAULT default_value ] ] [ , ... ] )
指定 UDF 的标识符 (
name
)、任何输入实参以及任何可选实参的默认值。对于标识符:
对于创建函数的架构,标识符不必唯一,因为 UDFs 是 通过名称和实参类型的组合来标识和解析的。
标识符必须以字母字符开头,且不能包含空格或特殊字符,除非整个标识符字符串放在双引号内(例如,"My object")。放在双引号内的标识符也区分大小写。请参阅 标识符要求。
对于输入实参:
对于
arg_name
,请指定输入实参的名称。对于
arg_data_type
,使用与所用处理程序语言相对应的 Snowflake 数据类型。有关 Java 处理程序,请参阅 SQL-Java 数据类型映射。
有关 Python 处理程序,请参阅 SQL-Python 数据类型映射。
有关 Scala 处理程序,请参阅 SQL-Scala 数据类型映射。
若要指示实参是可选的,请使用
DEFAULT default_value
指定实参的默认值。对于默认值,可以使用字面量或表达式。如果指定任何可选实参,则必须将这些实参放在必需实参之后。
如果函数具有可选实参,则无法定义具有相同名称和不同签名的其他函数。
有关详细信息,请参阅 指定可选实参。
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
值必须是使用处理程序支持的语言之一的源代码。代码可能包括:Java。有关更多信息,请参阅 Java UDFs 简介。
JavaScript。有关更多信息,请参阅 JavaScript UDFs 简介。
Python。有关更多信息,请参阅 Python UDFs 简介。
Scala。有关更多信息,请参阅 Scala UDFs 简介。
一个 SQL 表达式。有关更多信息,请参阅 SQL UDFs 简介。
有关更多详细信息,请参阅 `使用说明`_(本主题内容)。
备注
当在使用 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 FUNCTIONS 和 SHOW 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_name
是snowflake_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')
您可以通过在 Snowflake 中执行以下 SQL 来发现支持的系统包列表:
SELECT * FROM INFORMATION_SCHEMA.PACKAGES WHERE LANGUAGE = 'java';
对于使用 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')
您可以通过在 Snowflake 中执行以下 SQL 来发现支持的系统包列表:
SELECT * FROM INFORMATION_SCHEMA.PACKAGES WHERE LANGUAGE = 'python';
有关包含的包的更多信息,请参阅 使用第三方包。
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_name
是snowflake_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')
您可以通过在 Snowflake 中执行以下 SQL 来发现支持的系统包列表:
SELECT * FROM INFORMATION_SCHEMA.PACKAGES WHERE LANGUAGE = 'scala';
对于使用 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 覆盖现有文件。
访问控制要求¶
权限 |
对象 |
备注 |
---|---|---|
CREATE FUNCTION |
架构 |
|
USAGE |
函数 |
通过向角色授予对新创建函数的 USAGE 权限,具有该角色的用户可以在 Snowflake 中的其他位置调用该函数(例如,External Tokenization 的掩码策略所有者角色)。 |
USAGE |
外部访问集成 |
对于由 EXTERNAL_ACCESS_INTEGRATIONS 参数指定的集成(如果有)来说是必需的。有关更多信息,请参阅 CREATE EXTERNAL ACCESS INTEGRATION。 |
READ |
密钥 |
对于由 SECRETS 参数指定的密钥(如果有)来说是必需的。有关更多信息,请参阅 创建表示凭据的密钥 和 在函数或过程中使用外部访问集成。 |
USAGE |
架构 |
对于包含由 SECRETS 参数指定的密钥(如果有)的架构来说是必需的。有关更多信息,请参阅 创建表示凭据的密钥 和 在函数或过程中使用外部访问集成。 |
请注意,对架构中的对象进行操作还需要对父数据库和架构具有 USAGE 权限。
有关创建具有指定权限集的自定义角色的说明,请参阅 创建自定义角色。
使用说明¶
所有语言¶
function_definition
有大小限制。最大允许大小可能会发生变化。周围的
function_definition
分隔符可以是单引号或一对美元符号。使用
$$
作为分隔符可以更轻松地编写包含单引号的函数。如果函数主体的分隔符是单引号字符,则
function_definition
中的任何单引号(例如字符串字面量) :emph:` 必须 ` 用单引号转义。如果在 :doc:` 掩码策略 <create-masking-policy>` 中使用 UDF,请确保列的数据类型、UDF 和掩码策略匹配。有关更多信息,请参阅 掩码策略中的用户定义函数。
如果在 UDF 的处理程序代码中指定 CURRENT_DATABASE 或 CURRENT_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;
}
}';
以下是 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'
;
有关 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;
}
';
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__]
$$;
以下示例中的代码创建一个 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')
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
}
}
$$;
以下是 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';
有关 Scala UDFs 的更多示例,请参阅 Scala UDF 处理程序示例。
SQL¶
创建一个简单的 SQL 标量 UDF,它返回数学常量 pi 的硬编码近似值:
CREATE FUNCTION pi_udf()
RETURNS FLOAT
AS '3.141592654::FLOAT'
;
创建一个返回硬编码值的简单 SQL 表 UDF:
CREATE FUNCTION simple_table_function ()
RETURNS TABLE (x INTEGER, y INTEGER)
AS
$$
SELECT 1, 2
UNION ALL
SELECT 3, 4
$$
;
SELECT * FROM TABLE(simple_table_function());
输出:
SELECT * FROM TABLE(simple_table_function());
+---+---+
| X | Y |
|---+---|
| 1 | 2 |
| 3 | 4 |
+---+---+
创建一个接受多个参数的 UDF:
CREATE FUNCTION multiply1 (a number, b number)
RETURNS number
COMMENT='multiply two numbers'
AS 'a * b';
创建一个名为 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';