UDFs tabulares de SQL (UDTFs)

O Snowflake oferece suporte para UDFs de SQL que retornam um conjunto de linhas consistindo de 0, 1, ou várias linhas, cada uma com 1 ou mais colunas. Tais UDFs são chamadas de UDFs tabulares, UDFs de tabela ou, mais frequentemente, UDTFs (funções de tabela definidas pelo usuário).

Uma UDTF pode ser acessada na cláusula FROM de uma consulta.

Neste tópico:

Sintaxe

CREATE OR REPLACE FUNCTION <name> ( [ <arguments> ] )
  RETURNS TABLE ( <output_col_name> <output_col_type> [, <output_col_name> <output_col_type> ... ] )
  AS '<sql_expression>'
Copy

Para obter uma descrição mais detalhada da sintaxe geral para todas as UDFs, incluindo UDTFs de SQL, consulte CREATE FUNCTION.

Argumentos

name:

Deve ser um nome válido de objeto de banco de dados que segue as regras descritas em: Requisitos para identificadores.

arguments:

Deve ser uma expressão, por exemplo, um nome de coluna, um literal ou uma expressão que possa ser avaliada como um único valor. Normalmente, uma função requer um argumento, que é um nome de coluna. Você pode passar mais de um valor, por exemplo, mais de um nome de coluna, ou um nome de coluna e um ou mais valores literais.

É possível passar uma constante ou nenhum valor. Entretanto, na maioria dos casos, se a entrada for sempre a mesma, a saída será sempre a mesma.

RETURNS TABLE(...)

Especifica que a UDF deve retornar uma tabela. Dentro dos parênteses, especifique pares de nomes e tipos para colunas (como descrito abaixo) a serem incluídos na tabela retornada.

output_col_name:

O nome de uma coluna de saída a ser incluída na tabela retornada. Deve haver pelo menos uma coluna de saída.

output_col_type:

O tipo de dados da coluna de saída.

sql_expression:

Uma expressão ou instrução válida de SQL que retorna uma tabela com zero ou mais linhas, cada uma delas com uma ou mais colunas. As saídas devem corresponder ao número e aos tipos de dados especificados na cláusula RETURNS.

Notas de uso

  • O corpo principal (ou seja, a “definição”) de uma UDTF de SQL deve ser uma expressão SELECT.

  • Embora os delimitadores em torno da sql_expression geralmente sejam aspas simples, você pode usar um par de cifrões $$ como delimitador. O delimitador de fechamento deve corresponder ao delimitador de abertura. É conveniente usar um par de cifrões quando a sql_expression contém aspas simples. Um exemplo usando um par de cifrões está incluído na seção Exemplos abaixo.

    Se o delimitador for aspas simples e o corpo contiver uma única citação, você poderá escapar a citação única no corpo usando o caractere de barra invertida \ como caractere de escape. Um exemplo está incluído na seção Exemplos abaixo.

  • As colunas definidas na UDTF podem aparecer em qualquer lugar onde uma coluna de tabela normal pode ser usada.

  • Os tipos de retorno especificados na cláusula RETURNS determinam os nomes e tipos das colunas nos resultados tabulares e devem corresponder aos tipos das expressões nas posições correspondentes da instrução SELECT no corpo da função.

  • Ao chamar uma UDTF, você deve incluir o nome e os argumentos da UDTF dentro dos parênteses depois da palavra-chave TABLE. Para obter mais informações, consulte Como chamar uma UDTF de SQL.

Nota

Funções tabulares (UDTFs) têm um limite de 500 argumentos de entrada e 500 colunas de saída.

Como chamar uma UDTF de SQL

Ao chamar uma UDTF na cláusula FROM de uma consulta, especifique o nome e os argumentos da UDTF dentro dos parênteses que seguem a palavra-chave TABLE.

Em outras palavras, use um formulário como o seguinte para a palavra-chave TABLE quando chamar uma UDTF:

SELECT ...
  FROM TABLE ( udtf_name (udtf_arguments) )
Copy

Exemplos de UDTFs de SQL

Exemplos básicos

Esse é um exemplo artificialmente simples de uma UDTF com uma saída embutida no código. Ele também ilustra o uso de $$ como delimitador:

CREATE FUNCTION t()
    RETURNS TABLE(msg VARCHAR)
    AS
    $$
        SELECT 'Hello'
        UNION
        SELECT 'World'
    $$;
Copy
SELECT msg 
    FROM TABLE(t())
    ORDER BY msg;
+-------+
| MSG   |
|-------|
| Hello |
| World |
+-------+
Copy

Este exemplo é semelhante ao exemplo anterior, mas usa aspas simples como delimitador e usa o caractere de escape \ para escapar as aspas simples no corpo da UDTF:

CREATE FUNCTION t()
    RETURNS TABLE(msg VARCHAR)
    AS
    '
        SELECT \'Hello\'
        UNION
        SELECT \'World\'
    ';
Copy
SELECT msg
    FROM TABLE(t())
    ORDER BY msg;
+-------+
| MSG   |
|-------|
| Hello |
| World |
+-------+
Copy

Este é outro exemplo básico de uma UDTF. Ele consulta uma tabela e retorna duas das colunas dessa tabela:

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);
Copy
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
    $$
    ;
Copy
select product_id, quantity_sold
    from table(orders_for_product('compostable bags'))
    order by product_id;
+------------------+---------------+
| PRODUCT_ID       | QUANTITY_SOLD |
|------------------+---------------|
| compostable bags |       2000.00 |
+------------------+---------------+
Copy

Essa mesma funcionalidade também pode ser implementada usando uma exibição.

Exemplos com junções

Criar e usar uma UDTF de SQL que retorna informações do país (COUNTRY_CODE e COUNTRY_NAME) para uma ID de usuário especificada:

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');
Copy
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
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 |
+--------------+---------------+
Copy

Criar uma UDTF de SQL que retorna a cor favorita para um ano específico:

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;
Copy
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';
Copy

Usar a UDTF em uma consulta:

select color
    from table(favorite_colors(2017))
    order by color;
+--------+
| COLOR  |
|--------|
| orange |
| red    |
+--------+
Copy

Usar a UDTF em uma junção com outra tabela; observe que a coluna de junção da tabela é passada como argumento para a função.

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 |
+------+--------+
Copy

Usar uma cláusula WHERE, em vez de ON, para predicatos adicionais:

select * 
    from fashion f join table(favorite_colors(f.year)) fav
    where fav.color = f.fashion_color ;
+------+---------------+-------+
| YEAR | FASHION_COLOR | COLOR |
|------+---------------+-------|
| 2017 | red           | red   |
+------+---------------+-------+
Copy

Usar a UDTF com uma constante em uma expressão de junção; observe que uma cláusula WHERE, no lugar de ON, deve ser usada para condições adicionais de junção:

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        |
+---------------+------+---------------+
Copy