Como chamar uma UDF

Você pode chamar uma função definida pelo usuário (UDF) ou uma função de tabela definida pelo usuário (UDTF) da mesma forma que você chama outras funções.

Como chamar uma UDF

Em geral, você chama uma UDF da mesma forma que você chama outras funções.

Se uma UDF tiver argumentos, você pode especificar esses argumentos por nome ou por posição.

Por exemplo, a seguinte UDF aceita três argumentos:

CREATE OR REPLACE FUNCTION udf_concatenate_strings(
    first VARCHAR,
    second VARCHAR,
    third VARCHAR)
  RETURNS VARCHAR
  LANGUAGE SQL
  AS
  $$
    RETURN first || second || third;
  $$;
Copy

Ao chamar a UDF, você pode especificar os argumentos por nome:

SELECT udf_concatenate_strings(
  first => 'one',
  second => 'two',
  third => 'three');
Copy

Se você especificar os argumentos por nome, não precisará especificar os argumentos em nenhuma ordem específica:

SELECT udf_concatenate_strings(
  third => 'three',
  first => 'one',
  second => 'two');
Copy

Você também pode especificar os argumentos por posição:

SELECT udf_concatenate_strings(
  'one',
  'two',
  'three');
Copy

Observe o seguinte:

  • Você deve especificar todos os argumentos por nome ou por posição. Você não pode especificar alguns dos argumentos por nome e outros argumentos por posição.

    Ao especificar um argumento por nome, você não pode usar aspas duplas no nome do argumento.

  • Se duas funções ou dois procedimentos tiverem o mesmo nome, mas tipos de argumento diferentes, você poderá usar os nomes dos argumentos para especificar qual função ou procedimento executar, se os nomes dos argumentos forem diferentes. Consulte Sobrecarga de procedimentos e funções.

Como chamar uma UDF que possui argumentos opcionais

Se a UDF tiver argumentos opcionais, você poderá omitir os argumentos opcionais na chamada. Cada argumento opcional possui um valor padrão que é usado quando o argumento é omitido.

Por exemplo, a seguinte UDF tem um argumento obrigatório e dois argumentos opcionais. Cada argumento opcional possui um valor padrão.

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

Você pode omitir qualquer um dos argumentos opcionais na chamada. Quando você omite um argumento, o valor padrão do argumento é usado.

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

Se precisar omitir um argumento opcional e especificar outro argumento opcional que apareça após o argumento omitido na assinatura, use argumentos nomeados, em vez de argumentos posicionais.

Por exemplo, suponha que você queira omitir o argumento prefix e especificar o argumento suffix. O argumento suffix aparece após prefix na assinatura, portanto você deve especificar os argumentos por nome:

SELECT build_string_udf(word => 'hello', suffix => '-after');
Copy
+-------------------------------------------------------+
| BUILD_STRING_UDF(WORD => 'HELLO', SUFFIX => '-AFTER') |
|-------------------------------------------------------|
| pre-hello-after                                       |
+-------------------------------------------------------+

Como chamar uma UDTF

Você pode chamar uma UDTF da mesma forma como você chamaria qualquer função de tabela. 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, como você faria ao chamar uma função de tabela interna.

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

O código no exemplo a seguir chama a função de tabela my_java_udtf, especificando um literal DATE no argumento '2021-01-16'::DATE.

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

O argumento para uma função de tabela pode ser uma expressão e não apenas um literal. Por exemplo, uma função de tabela pode ser chamada usando uma coluna de uma tabela. Alguns exemplos estão abaixo, inclusive na seção Exemplos.

Assim como ao chamar UDFs, você pode especificar os argumentos por nome ou por posição.

Para obter mais informações sobre as funções de tabela em geral, consulte função de tabela.

Nota

Você não pode chamar uma UDF dentro da cláusula DEFAULT de uma instrução CREATE TABLE.

Como usar uma tabela ou UDTF como entrada para uma UDTF

A entrada para uma função de tabela pode vir de uma tabela ou de outra UDTF, como documentado em Como usar uma tabela como entrada para uma função de tabela.

O exemplo abaixo mostra como utilizar uma tabela para fornecer entrada para a 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

A saída se assemelha ao seguinte:

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

A cláusula IMPORTS da UDTF deve especificar o nome e o caminho de cada arquivo passado para a UDTF. Por exemplo:

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

Cada arquivo já deve ter sido copiado para um estágio (neste caso, o estágio denominado @inline_jars) antes que a UDTF leia o arquivo.

Para obter um exemplo de uso de uma UDTF como entrada para outra UDTF, consulte Exemplos estendidos usando valores de tabela e outras UDTFs como entrada na documentação UDTF de JavaScript.

Funções de tabela e partições

Antes que linhas sejam passadas para funções de tabela, elas podem ser agrupadas em partições. A criação de partições tem dois benefícios principais:

  • A criação de partições permite que o Snowflake divida a carga de trabalho para melhorar a paralelização e, assim, o desempenho.

  • A criação de partições permite que o Snowflake processe todas as linhas com uma característica comum como um grupo. Você pode retornar resultados que são baseados em todas as linhas do grupo e não apenas em linhas individuais.

Por exemplo, você pode particionar dados de preços de ações em um grupo por ação. Todos os preços de ações de uma empresa individual podem ser analisados em conjunto, enquanto os preços das ações de cada empresa podem ser analisados independentemente de qualquer outra empresa.

Dados podem ser particionados de forma explícita ou implícita.

Particionamento explícito

Particionamento explícito em vários grupos

A instrução a seguir chama a UDTF chamada my_udtf em partições individuais. Cada partição contém todas as linhas para as quais a expressão PARTITION BY é avaliada como o mesmo valor (por exemplo, a mesma empresa ou símbolo de ação).

SELECT *
    FROM stocks_table AS st,
         TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY st.symbol))
Copy

Particionamento explícito em um único grupo

A instrução a seguir chama a UDTF chamada my_udtf em uma partição. A cláusula PARTITION BY <constante> (neste caso PARTITION BY 1) coloca todas as linhas na mesma partição.

SELECT *
    FROM stocks_table AS st,
         TABLE(my_udtf(st.symbol, st.transaction_date, st.price) OVER (PARTITION BY 1))
Copy

Para obter um exemplo mais completo e realista, consulte Exemplos de como chamar UDTFs de Java em consultas, em particular a subseção intitulada Partição única.

Como ordenar linhas para partições

Para processar as linhas de cada partição em uma ordem especificada, inclua uma cláusula ORDER BY. Isso diz ao Snowflake para passar as linhas para o método do manipulador por linha na ordem especificada.

Por exemplo, se você quiser calcular a média móvel do preço de uma ação ao longo do tempo, ordene os preços das ações por carimbo de data/hora (e particione por símbolo de ação). O exemplo a seguir mostra como fazer isso:

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

Uma cláusula OVER pode conter uma cláusula ORDER BY mesmo sem uma cláusula PARTITION BY.

Lembre-se de que incluir uma cláusula ORDER BY dentro de uma cláusula OVER não é o mesmo que colocar uma cláusula ORDER BY no nível mais externo da consulta. Se você quiser que todos os resultados da consulta sejam encomendados, você precisa de uma cláusula ORDER BY separada. Por exemplo:

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

Notas de uso para particionamento explícito

Ao utilizar uma UDTF com uma cláusula PARTITION BY, a cláusula PARTITION BY deve utilizar uma referência de coluna ou uma expressão literal, não uma expressão geral. Por exemplo, o seguinte não é permitido:

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

Particionamento implícito

Se uma função de tabela não particiona explicitamente as linhas usando uma cláusula PARTITION BY, o Snowflake normalmente divide as linhas implicitamente para usar processamento paralelo para melhorar o desempenho.

O número de partições normalmente é baseado em fatores como o tamanho do warehouse que processa a função e a cardinalidade da relação de entrada. As linhas normalmente são atribuídas a partições específicas com base em fatores como a localização física das linhas (por exemplo, por micropartição), de modo que o agrupamento da partição não tem significado.