表格 SQL UDFs (UDTFs)¶
Snowflake 支持此类 SQL UDFs:返回一组行,其中包含零行、一行或多行,并且每行有一列或多列。此类 UDFs 称为*表格 UDFs*、表 UDFs 或最常见的 *UDTFs*(用户定义的表函数)。
可以在查询的 FROM 子句中访问 UDTF。
本主题内容:
语法¶
CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
RETURNS TABLE ( <output_col_name> <output_col_type> [, <output_col_name> <output_col_type> ... ] )
AS '<sql_expression>'
有关所有 UDFs 的通用语法的更详细描述(包括 SQL UDTFs),请参阅 CREATE FUNCTION。
实参¶
name
:这应该是有效数据库对象名称(遵循:doc:`/sql-reference/identifiers-syntax`中描述的规则)。
arguments
:这必须是一个表达式,例如列名称、字面量或可计算为单个值的表达式。通常,函数接受一个实参,即列名称。可以传递多个值,例如,多个列名称,或者一个列名称和一个或多个字面量值。
可以传递常量值或根本不传递值。但是,在大多数情况下,如果每次的输入都相同,则每次的输出都会相同。
RETURNS TABLE(...)
指定 UDF 应返回表。在括号内,指定要包含在返回表中的列的名称类型对(如下所述)。
output_col_name
:要包含在返回表中的输出列的名称。必须至少有一个输出列。
output_col_type
:输出列的数据类型。
sql_expression
:一个有效的 SQL 表达式或语句,返回具有零行或多行的表,并且每行都有一列或多列。输出必须与 RETURNS 子句中指定的数字和数据类型匹配。
使用说明¶
SQL UDTF 的主体(也称为“定义”)必须是一个 SELECT 表达式。
尽管
sql_expression
周围的分隔符通常是单引号,但可以使用一对美元符号$$
作为分隔符。结束分隔符必须与开始分隔符匹配。当sql_expression
包含单引号时,使用一对美元符号会很方便。下面的示例部分包含了使用一对美元符号的示例。如果分隔符是单引号,并且主体包含单引号,则可以使用反斜杠字符
\
作为转义字符来转义主体中的单引号。下面的示例部分包含一个示例。在 UDTF 中定义的列可以出现在可使用普通表列的任何位置。
在 RETURNS 子句中指定的返回类型决定了表格结果中列的名称和类型,并且必须匹配位于函数主体中 SELECT 语句的相应位置的表达式类型。
调用 UDTF 时,必须在 TABLE 关键字后面的括号内包含 UDTF 名称和实参。有关详细信息,请参阅:ref:label-udf_java_call_udtf。
备注
表格函数 (UDTFs) 的输入实参限制为 500 个,输出列限制为 500 列。
调用 SQL UDTF¶
在查询的 FROM 子句中调用 UDTF 时,请在 TABLE 关键字后面的括号内指定 UDTF 的名称和实参。
换言之,在调用 UDTF 时,对 TABLE 关键字使用如下形式:
SELECT ...
FROM TABLE ( udtf_name (udtf_arguments) )
示例 SQL UDTFs¶
基本示例¶
这是一个人为简化的示例 UDTF,它对输出进行硬编码。此示例也展示了用作分隔符的 $$
:
CREATE FUNCTION t()
RETURNS TABLE(msg VARCHAR)
AS
$$
SELECT 'Hello'
UNION
SELECT 'World'
$$;
SELECT msg
FROM TABLE(t())
ORDER BY msg;
+-------+
| MSG |
|-------|
| Hello |
| World |
+-------+
以下示例与前一个示例类似,但它使用单引号作为分隔符,并使用 \
转义字符对 UDTF 主体中的单引号进行转义:
CREATE FUNCTION t()
RETURNS TABLE(msg VARCHAR)
AS
'
SELECT \'Hello\'
UNION
SELECT \'World\'
';
SELECT msg
FROM TABLE(t())
ORDER BY msg;
+-------+
| MSG |
|-------|
| Hello |
| World |
+-------+
以下是 UDTF 的另一个简单示例。它查询一个表,并从该表中返回两列:
create or replace table orders (
product_id varchar,
quantity_sold numeric(11, 2)
);
insert into orders (product_id, quantity_sold) values
('compostable bags', 2000),
('re-usable cups', 1000);
create or replace function orders_for_product(PROD_ID varchar)
returns table (Product_ID varchar, Quantity_Sold numeric(11, 2))
as
$$
select product_ID, quantity_sold
from orders
where product_ID = PROD_ID
$$
;
select product_id, quantity_sold
from table(orders_for_product('compostable bags'))
order by product_id;
+------------------+---------------+
| PRODUCT_ID | QUANTITY_SOLD |
|------------------+---------------|
| compostable bags | 2000.00 |
+------------------+---------------+
也可以使用视图实现相同的功能。
使用联接的示例¶
创建并使用一个 SQL UDTF,其返回指定用户 ID 的国家/地区信息(COUNTRY_CODE
和 COUNTRY_NAME
):
create or replace table countries (country_code char(2), country_name varchar);
insert into countries (country_code, country_name) values
('FR', 'FRANCE'),
('US', 'UNITED STATES'),
('SP', 'SPAIN');
create or replace table user_addresses (user_ID integer, country_code char(2));
insert into user_addresses (user_id, country_code) values
(100, 'SP'),
(123, 'FR'),
(123, 'US');
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';
select *
from table(get_countries_for_user(123)) cc
where cc.country_code in ('US','FR','CA')
order by country_code;
+--------------+---------------+
| COUNTRY_CODE | COUNTRY_NAME |
|--------------+---------------|
| FR | FRANCE |
| US | UNITED STATES |
+--------------+---------------+
创建一个 SQL UDTF,以返回指定年份最热门的颜色:
create or replace table favorite_years as
select 2016 year
UNION ALL
select 2017
UNION ALL
select 2018
UNION ALL
select 2019;
create or replace table colors as
select 2017 year, 'red' color, true favorite
UNION ALL
select 2017 year, 'orange' color, true favorite
UNION ALL
select 2017 year, 'green' color, false favorite
UNION ALL
select 2018 year, 'blue' color, true favorite
UNION ALL
select 2018 year, 'violet' color, true favorite
UNION ALL
select 2018 year, 'brown' color, false favorite;
create or replace table fashion as
select 2017 year, 'red' fashion_color
UNION ALL
select 2018 year, 'black' fashion_color
UNION ALL
select 2019 year, 'orange' fashion_color;
create or replace function favorite_colors(the_year int)
returns table(color string) as
'select color from colors where year=the_year and favorite=true';
在查询中使用 UDTF:
select color
from table(favorite_colors(2017))
order by color;
+--------+
| COLOR |
|--------|
| orange |
| red |
+--------+
在与另一个表的联接中使用 UDTF;请注意,表中的联接列将作为实参传递给函数。
select *
from favorite_years y join table(favorite_colors(y.year)) c
order by year, color;
+------+--------+
| YEAR | COLOR |
|------+--------|
| 2017 | orange |
| 2017 | red |
| 2018 | blue |
| 2018 | violet |
+------+--------+
使用 WHERE 子句而不是 ON 来表示其他谓词:
select *
from fashion f join table(favorite_colors(f.year)) fav
where fav.color = f.fashion_color ;
+------+---------------+-------+
| YEAR | FASHION_COLOR | COLOR |
|------+---------------+-------|
| 2017 | red | red |
+------+---------------+-------+
在联接表达式中,将 UDTF 与常量一起使用;请注意,必须使用 WHERE 子句而不是 ON 来表示其他联接条件:
select fav.color as favorite_2017, f.*
from fashion f JOIN table(favorite_colors(2017)) fav
where fav.color = f.fashion_color
order by year;
+---------------+------+---------------+
| FAVORITE_2017 | YEAR | FASHION_COLOR |
|---------------+------+---------------|
| red | 2017 | red |
| orange | 2019 | orange |
+---------------+------+---------------+