调用 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
  $$;
Copy

调用 UDF 时,可以按名称指定实参:

SELECT udf_concatenate_strings(
  first_arg => 'one',
  second_arg => 'two',
  third_arg => 'three');
Copy
+--------------------------+
| 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');
Copy
+--------------------------+
| UDF_CONCATENATE_STRINGS( |
|   THIRD_ARG => 'THREE',  |
|   FIRST_ARG => 'ONE',    |
|   SECOND_ARG => 'TWO')   |
|--------------------------|
| onetwothree              |
+--------------------------+

您还可以按位置指定实参:

SELECT udf_concatenate_strings(
  'one',
  'two',
  'three');
Copy
+--------------------------+
| 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
  $$
  ;
Copy

您可以在调用中省略任何可选实参。省略实参时,将使用该实参的默认值。

SELECT build_string_udf('hello');
Copy
+---------------------------+
| BUILD_STRING_UDF('HELLO') |
|---------------------------|
| pre-hello-post            |
+---------------------------+
SELECT build_string_udf('hello', 'before-');
Copy
+--------------------------------------+
| BUILD_STRING_UDF('HELLO', 'BEFORE-') |
|--------------------------------------|
| before-hello-post                    |
+--------------------------------------+

如果需要省略可选实参,并在签名中指定出现在被省略实参之后的另一个可选实参,请使用命名实参,而不是位置实参。

例如,假设您要省略 prefix 实参,并指定 suffix 实参。suffix 实参显示在签名中的 prefix 之后,因此必须按名称指定实参:

SELECT build_string_udf(word => 'hello', suffix => '-after');
Copy
+-------------------------------------------------------+
| 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) )
Copy

以下示例中的代码调用 my_java_udtf 表函数,并在 '2021-01-16'::DATE 实参中指定 DATE 字面量。

SELECT ...
  FROM TABLE(my_java_udtf('2021-01-16'::DATE));
Copy

表函数的实参可以是表达式,而不仅仅是字面量。例如,可以使用表中的列调用表函数。以下是一些示例,包括 示例部分 中的示例。

调用 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;
Copy

输出看起来类似于以下内容:

+-------------------+------------+
| FILE_NAME         | WORD       |
+-------------------+------------+
| sample_data.txt   | some       |
| sample_data.txt   | words      |
| sample_data_2.txt | additional |
| sample_data_2.txt | words      |
+-------------------+------------+
Copy

UDTF 的 IMPORTS 子句必须指定传递给 UDTF 的 每个 文件的名称和路径。例如:

create function split_file_into_words(inputFileName string)
    ...
    imports = ('@inline_jars/sample.txt', '@inline_jars/sample_2.txt')
    ...
Copy

在 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))
Copy

显式分区为单个组

以下语句在单个分区上调用命名为 UDTF 的 my_udtfPARTITION 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))
Copy

有关更完整和更现实的示例,请参阅 在查询中调用 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))
Copy

即使没有 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;
Copy

显式分区的使用说明

将 UDTF 与 PARTITION BY 子句一起使用时,PARTITION BY 子句必须使用列引用或字面量,而不是通用表达式。例如, 允许出现以下情况:

SELECT * FROM udtf_table, TABLE(my_func(col1) OVER (PARTITION BY udtf_table.col2 * 2));   -- NO!
Copy

隐式分区

如果表函数未使用 PARTITION BY 子句显式分区行,则 Snowflake 通常会隐式分区行,以使用并行处理来提高性能。

分区数通常基于仓库大小、处理函数和输入关系的基数等因素。通常根据行的物理位置(例如通过微分区)等因素将行分配给特定分区,因此分区分组没有意义。

语言: 中文