调用 UDF¶
您可以像调用其他函数一样调用用户定义函数 (UDF) 或用户定义表函数 (UDTF)。
调用 UDF¶
通常,调用 UDF 的方式与调用其他函数的方式相同。
如果 UDF 具有实参,则可以按名称或位置指定这些实参。
例如,以下 UDF 接受三个实参:
CREATE OR REPLACE FUNCTION udf_concatenate_strings(
first_arg VARCHAR,
second_arg VARCHAR,
third_arg VARCHAR)
RETURNS VARCHAR
LANGUAGE SQL
AS
$$
SELECT first_arg || second_arg || third_arg
$$;
调用 UDF 时,可以按名称指定实参:
SELECT udf_concatenate_strings(
first_arg => 'one',
second_arg => 'two',
third_arg => 'three');
+--------------------------+
| UDF_CONCATENATE_STRINGS( |
| FIRST_ARG => 'ONE', |
| SECOND_ARG => 'TWO', |
| THIRD_ARG => 'THREE') |
|--------------------------|
| onetwothree |
+--------------------------+
如果按名称指定实参,则不需要按任何特定顺序指定实参:
SELECT udf_concatenate_strings(
third_arg => 'three',
first_arg => 'one',
second_arg => 'two');
+--------------------------+
| UDF_CONCATENATE_STRINGS( |
| THIRD_ARG => 'THREE', |
| FIRST_ARG => 'ONE', |
| SECOND_ARG => 'TWO') |
|--------------------------|
| onetwothree |
+--------------------------+
您还可以按位置指定实参:
SELECT udf_concatenate_strings(
'one',
'two',
'three');
+--------------------------+
| UDF_CONCATENATE_STRINGS( |
| 'ONE', |
| 'TWO', |
| 'THREE') |
|--------------------------|
| onetwothree |
+--------------------------+
请注意以下事项:
必须按名称或位置指定所有实参。不能按名称指定某些实参,也不能按位置指定其他实参。
按名称指定实参时,不能在实参名称前后使用双引号。
如果两个函数或两个过程的名称相同但实参类型不同,那么在实参名称不同的情况下,可以使用实参名称来指定要执行的函数或过程。请参阅 重载过程和函数。
调用具有可选实参的 UDF¶
如果 UDF 具有 可选实参,则可以在调用中省略可选实参。每个可选实参都有一个默认值,当省略该实参时将使用该默认值。
例如,以下 UDF 具有一个必填实参和两个可选实参。每个可选实参都有一个默认值。
CREATE OR REPLACE FUNCTION build_string_udf(
word VARCHAR,
prefix VARCHAR DEFAULT 'pre-',
suffix VARCHAR DEFAULT '-post'
)
RETURNS VARCHAR
AS
$$
SELECT prefix || word || suffix
$$
;
您可以在调用中省略任何可选实参。省略实参时,将使用该实参的默认值。
SELECT build_string_udf('hello');
+---------------------------+
| BUILD_STRING_UDF('HELLO') |
|---------------------------|
| pre-hello-post |
+---------------------------+
SELECT build_string_udf('hello', 'before-');
+--------------------------------------+
| BUILD_STRING_UDF('HELLO', 'BEFORE-') |
|--------------------------------------|
| before-hello-post |
+--------------------------------------+
如果需要省略可选实参,并在签名中指定出现在被省略实参之后的另一个可选实参,请使用命名实参,而不是位置实参。
例如,假设您要省略 prefix
实参,并指定 suffix
实参。suffix
实参显示在签名中的 prefix
之后,因此必须按名称指定实参:
SELECT build_string_udf(word => 'hello', suffix => '-after');
+-------------------------------------------------------+
| BUILD_STRING_UDF(WORD => 'HELLO', SUFFIX => '-AFTER') |
|-------------------------------------------------------|
| pre-hello-after |
+-------------------------------------------------------+
调用 UDTF¶
您可以像调用任何表函数一样调用 UDTF。在查询的 FROM 子句中调用 UDTF 时,请在 TABLE 关键字后面的括号内指定 UDTF 的名称和实参,就像 调用内置表函数 时一样。
换言之,在调用 UDTF 时,对 TABLE 关键字使用如下形式:
SELECT ...
FROM TABLE ( udtf_name (udtf_arguments) )
以下示例中的代码调用 my_java_udtf
表函数,并在 '2021-01-16'::DATE
实参中指定 DATE 字面量。
SELECT ...
FROM TABLE(my_java_udtf('2021-01-16'::DATE));
表函数的实参可以是表达式,而不仅仅是字面量。例如,可以使用表中的列调用表函数。以下是一些示例,包括 示例部分 中的示例。
与 调用 UDFs 一样,可以通过名称或位置来指定实参。
有关表函数的一般信息,请参阅 表函数。
备注
不能在 CREATE TABLE 语句的 DEFAULT 子句中调用 UDF。
使用表或 UDTF 作为 UDTF 的输入¶
表函数的输入可以来自一个表,也可以来自另一个 UDTF,如 使用表作为表函数的输入 中所述。
以下示例演示如何使用表向 UDTF split_file_into_words
提供输入:
create table file_names (file_name varchar);
insert into file_names (file_name) values ('sample.txt'),
('sample_2.txt');
select f.file_name, w.word
from file_names as f, table(split_file_into_words(f.file_name)) as w;
输出看起来类似于以下内容:
+-------------------+------------+
| FILE_NAME | WORD |
+-------------------+------------+
| sample_data.txt | some |
| sample_data.txt | words |
| sample_data_2.txt | additional |
| sample_data_2.txt | words |
+-------------------+------------+
UDTF 的 IMPORTS 子句必须指定传递给 UDTF 的 每个 文件的名称和路径。例如:
create function split_file_into_words(inputFileName string)
...
imports = ('@inline_jars/sample.txt', '@inline_jars/sample_2.txt')
...
在 UDTF 读取文件之前,每个文件必须已复制到一个暂存区(在本例中,暂存区的名称为 @inline_jars
)。
请参阅 JavaScript UDTF 文档中的 使用表值和其他 UDTFs 作为输入的扩展示例,其中提供了将 UDTF 用作另一个 UDTF 的输入的示例。
表函数和分区¶
在将行传递给表函数之前,可以将行分组到*分区*中。分区有两个主要优势:
分区允许 Snowflake 划分工作负载,以提高并行化,从而提高性能。
分区允许 Snowflake 将具有共同特征的所有行作为一个组进行处理。您可以返回基于组中所有行的结果,而不仅仅是单个行。
例如,可以按每只股票一组的形式对股票价格数据进行分区。单个公司的所有股票价格都可以一起分析,而每个公司的股票价格可以独立于任何其他公司进行分析。
可以显式或隐式对数据进行分区。
显式分区¶
显式分区为多个组
以下语句在各个分区上调用命名为 my_udtf
的 UDTF。每个分区都包含 PARTITION BY
表达式计算结果为相同值(例如,相同的公司或股票代码)的所有行。
SELECT *
FROM stocks_table AS st,
TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY st.symbol))
显式分区为单个组
以下语句在单个分区上调用命名为 UDTF 的 my_udtf
。PARTITION BY <constant>
子句(在本例中为 PARTITION BY 1
)将所有行放在同一个分区中。
SELECT *
FROM stocks_table AS st,
TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY 1))
有关更完整和更现实的示例,请参阅 在查询中调用 Java UDTFs 的示例,特别是标题为 单个分区 的小节。
对分区的行进行排序
若要按指定顺序处理每个分区的行,请包含一个 ORDER BY 子句。这会告诉 Snowflake 按指定的顺序将行传递给每行处理程序方法。
例如,如果要计算股票价格随时间变化的移动平均线,则按时间戳(并按股票代码分区)对股票价格进行排序。以下示例演示如何执行此操作:
SELECT *
FROM stocks_table AS st,
TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY st.symbol ORDER BY st.transaction_date))
即使没有 PARTITION BY 子句, OVER 子句也可以包含 ORDER BY 子句。
请记住,在 OVER 子句中包含 ORDER BY 子句与将 ORDER BY 子句放在查询的最外层不同。如果要对整个查询结果进行排序,则需要一个单独的 ORDER BY 子句。例如:
SELECT *
FROM stocks_table AS st,
TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY st.symbol ORDER BY st.transaction_date))
ORDER BY st.symbol, st.transaction_date, st.transaction_time;
显式分区的使用说明
将 UDTF 与 PARTITION BY 子句一起使用时,PARTITION BY 子句必须使用列引用或字面量,而不是通用表达式。例如,不 允许出现以下情况:
SELECT * FROM udtf_table, TABLE(my_func(col1) OVER (PARTITION BY udtf_table.col2 * 2)); -- NO!
隐式分区¶
如果表函数未使用 PARTITION BY 子句显式分区行,则 Snowflake 通常会隐式分区行,以使用并行处理来提高性能。
分区数通常基于仓库大小、处理函数和输入关系的基数等因素。通常根据行的物理位置(例如通过微分区)等因素将行分配给特定分区,因此分区分组没有意义。