SnowConvert AI - SQL Server - CREATE FUNCTION

Referência de tradução para funções definidas pelo usuário do Transact-SQL

Applies to
  • SQL Server

  • Azure Synapse Analytics

Descrição

O SQL Server suporta apenas dois tipos de Funções Definidas pelo Usuário:

Usando esses tipos de UDFs, é possível subcategorizá-los em simples e complexos, de acordo com a lógica interna.

UDFs simples, corresponde a sintaxe do SQL Server à sintaxe do Snowflake. Este tipo não adiciona nenhuma lógica e vai direto para o resultado. Estes são geralmente correspondentes a UDFs SQL do Snowflake. SnowConvert é compatível com a tradução de funções escalares definidas pelo usuário do SQL Server diretamente para UDFs do Script Snowflake quando cumprem critérios específicos.\ \ UDFs complexas, faz uso extensivo de determinadas instruções (INSERT, DELETE, UPDATE, SET, DECLARE, etc) ou control-of-flow bloqueia (IF…ELSE, WHILE, etc) e geralmente representa uma incompatibilidade ou violação da definição de UDFs SQL do Snowflake.

Limitações

Transact UDFs têm algumas limitações que não estão presentes em outros mecanismos de banco de dados (como Oracle e Teradata). Essas limitações ajudam as conversões ao restringirem o escopo da falha. Isso significa que há cenários específicos que podemos esperar evitar.

Aqui estão algumas das limitações que o SQL Server tem sobre UDFs

  • UDFs não podem ser usados para executar ações que modifiquem o estado do banco de dados

  • As funções definidas pelo usuário não podem conter uma cláusula OUTPUT INTO que tenha uma tabela como destino

  • As funções definidas pelo usuário não podem retornar vários conjuntos de resultados. Use um procedimento armazenado se você precisar retornar vários conjuntos de resultados.

Para obter a lista completa, consulte este link Criar funções definidas pelo usuário (mecanismo de banco de dados)

scalar.md

inline-table-valued.md

INLINE TABLE-VALUED

Referência de tradução para converter UDF (funções definidas pelo usuário) do Transact-SQL com o tipo de retorno TABLE em Snowflake.

Applies to
  • SQL Server

  • Azure Synapse Analytics

Descrição

Nota

Algumas partes do código de saída foram omitidas por motivos de clareza.

As funções Inline Table-Valued são expressões de tabela que podem aceitar parâmetros, executar uma instrução SELECT e retornar um TABLE (Referência da linguagem SQL Server - Criar uma função Inline Table-Valued).

Sintaxe do Transact

 -- Transact-SQL Inline Table-Valued Function Syntax
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
    [ = default ] [ READONLY ] }
    [ ,...n ]
  ]
)
RETURNS TABLE
    [ WITH <function_option> [ ,...n ] ]
    [ AS ]
    RETURN [ ( ] select_stmt [ ) ]
[ ; ]
Copy

Sintaxe do Snowflake SQL

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

Amostra de padrões da origem

A seção a seguir descreve todos os possíveis padrões de código-fonte que podem aparecer nesse tipo de sintaxe CREATE FUNCTION.

Para funções Inline Table-Valued, só pode haver uma instrução por corpo, que pode ser:

  • Instrução SELECT

  • Expressão de tabela comum WITH

Selecionar e retornar valores diretamente de uma tabela

Este é o cenário mais simples, executando uma seleção simples de uma tabela e retornando esses valores

Transact-SQL
com valor de tabela inline
CREATE FUNCTION GetDepartmentInfo()
RETURNS TABLE
AS
RETURN
(
  SELECT DepartmentID, Name, GroupName
  FROM HumanResources.Department
);

GO

SELECT * from GetDepartmentInfo()
Copy
Resultado

DepartmentID

Nome

GroupName

1

Engenharia

Pesquisa e desenvolvimento

2

Projeto de ferramentas

Pesquisa e desenvolvimento

3

Vendas

Vendas e marketing

4

Marketing

Vendas e marketing

5

Compras

Gerenciamento de Inventário

6

Pesquisa e desenvolvimento

Pesquisa e desenvolvimento

7

Produção

Fabricação

8

Controle de produção

Fabricação

9

Recursos Humanos

Executivo Geral e Administração

10

Finance

Executivo Geral e Administração

11

Serviços de informação

Executivo Geral e Administração

12

Controle de documentos

Garantia de Qualidade

13

Garantia de Qualidade

Garantia de Qualidade

14

Instalações e manutenção

Executivo Geral e Administração

15

Expedição e recebimento

Gerenciamento de Inventário

16

Executivo

Executivo Geral e Administração

Snowflake SQL
com valor de tabela inline
CREATE OR REPLACE FUNCTION GetDepartmentInfo ()
RETURNS TABLE(
  DepartmentID STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN DepartmentID WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
  Name STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN Name WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
  GroupName STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN GroupName WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
$$
    SELECT
    CAST(DepartmentID AS STRING),
    CAST(Name AS STRING),
    CAST(GroupName AS STRING)
    FROM
    HumanResources.Department
$$;

SELECT
    *
from
    TABLE(GetDepartmentInfo());
Copy
Resultado

DepartmentID

Nome

GroupName

1

Engenharia

Pesquisa e desenvolvimento

2

Projeto de ferramentas

Pesquisa e desenvolvimento

3

Vendas

Vendas e marketing

4

Marketing

Vendas e marketing

5

Compras

Gerenciamento de Inventário

6

Pesquisa e desenvolvimento

Pesquisa e desenvolvimento

7

Produção

Fabricação

8

Controle de produção

Fabricação

9

Recursos Humanos

Executivo Geral e Administração

10

Finance

Executivo Geral e Administração

11

Serviços de informação

Executivo Geral e Administração

12

Controle de documentos

Garantia de Qualidade

13

Garantia de Qualidade

Garantia de Qualidade

14

Instalações e manutenção

Executivo Geral e Administração

15

Expedição e recebimento

Gerenciamento de Inventário

16

Executivo

Executivo Geral e Administração

Selecionar e retornar valores de várias tabelas renomeando colunas e usando funções incorporadas

Este é um exemplo de uma consulta que usa funções internas em uma instrução Select, obtendo dados de diferentes tabelas, renomeando colunas e retornando uma tabela.

Transact-SQL
com valor de tabela inline
CREATE FUNCTION GetPersonBasicInfo()
RETURNS TABLE
AS 
RETURN
( 
 SELECT TOP (20)
      P.PersonType,
      P.FirstName,
      E.JobTitle,
   E.Gender,
      YEAR(E.HireDate) as HIREYEAR
  FROM 
      Person.Person P
  INNER JOIN 
      HumanResources.Employee E
  ON
      P.BusinessEntityID = E.BusinessEntityID 
);

GO

SELECT * FROM GetPersonBasicInfo();
Copy
Resultado

PersonType

FirstName

JobTitle

Gênero

HIREYEAR

EM

Ken

Diretor executivo

M

2009

EM

Terri

Vice-presidente de engenharia

F

2008

EM

Roberto

Gerente de engenharia

M

2007

EM

Rob

Desenvolvedor de ferramentas sênior

M

2007

EM

Gail

Engenheiro de design

F

2008

EM

Jossef

Engenheiro de design

M

2008

EM

Dylan

Gerente de pesquisa e desenvolvimento

M

2009

EM

Diane

Engenheira de pesquisa e desenvolvimento

F

2008

EM

Gigi

Engenheira de pesquisa e desenvolvimento

F

2009

EM

Michael

Gerente de pesquisa e desenvolvimento

M

2009

EM

Ovidiu

Desenvolvedor de ferramentas sênior

M

2010

EM

Thierry

Designer de ferramentas

M

2007

EM

Janice

Designer de ferramentas

F

2010

EM

Michael

Engenheira de design sênior

M

2010

EM

Sharon

Engenheiro de design

F

2011

EM

David

Gerente de marketing

M

2007

EM

Kevin

Assistente de marketing

M

2007

EM

John

Especialista de marketing

M

2011

EM

Mary

Assistente de marketing

F

2011

EM

Wanida

Assistente de marketing

F

2011

Snowflake SQL
com valor de tabela inline
CREATE OR REPLACE FUNCTION GetPersonBasicInfo ()
RETURNS TABLE(
 PersonType STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN PersonType WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
 FirstName STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN FirstName WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
 JobTitle STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN JobTitle WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
 Gender STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN Gender WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
 HIREYEAR INTEGER
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
AS
$$
  SELECT
  TOP 20
  CAST(P.PersonType AS STRING),
  CAST(P.FirstName AS STRING),
  CAST(E.JobTitle AS STRING),
  CAST(E.Gender AS STRING),
  YEAR(E.HireDate :: TIMESTAMP) as HIREYEAR
   FROM
  Person.Person P
   INNER JOIN
   HumanResources.Employee E
   ON P.BusinessEntityID = E.BusinessEntityID
$$;

SELECT
  *
FROM
  TABLE(GetPersonBasicInfo());
Copy
Resultado

PersonType

FirstName

JobTitle

Gênero

HIREYEAR

EM

Ken

Diretor executivo

M

2009

EM

Terri

Vice-presidente de engenharia

F

2008

EM

Roberto

Gerente de engenharia

M

2007

EM

Rob

Desenvolvedor de ferramentas sênior

M

2007

EM

Gail

Engenheiro de design

F

2008

EM

Jossef

Engenheiro de design

M

2008

EM

Dylan

Gerente de pesquisa e desenvolvimento

M

2009

EM

Diane

Engenheira de pesquisa e desenvolvimento

F

2008

EM

Gigi

Engenheira de pesquisa e desenvolvimento

F

2009

EM

Michael

Gerente de pesquisa e desenvolvimento

M

2009

EM

Ovidiu

Desenvolvedor de ferramentas sênior

M

2010

EM

Thierry

Designer de ferramentas

M

2007

EM

Janice

Designer de ferramentas

F

2010

EM

Michael

Engenheira de design sênior

M

2010

EM

Sharon

Engenheiro de design

F

2011

EM

David

Gerente de marketing

M

2007

EM

Kevin

Assistente de marketing

M

2007

EM

John

Especialista de marketing

M

2011

EM

Mary

Assistente de marketing

F

2011

EM

Wanida

Assistente de marketing

F

2011

Selecionar colunas usando a instrução WITH

O corpo de uma função com valor de tabela em linha também pode ser especificado usando uma instrução WITH, conforme mostrado abaixo.

Transact-SQL
com valor de tabela inline
CREATE FUNCTION GetMaritalStatusByGender
(
 @P_Gender nchar(1)
)

RETURNS TABLE 
AS
RETURN
(
  WITH CTE AS 
 (
  SELECT BusinessEntityID, MaritalStatus, Gender 
  FROM HumanResources.Employee 
  where Gender = @P_Gender
 ) 
  SELECT 
 MaritalStatus, Gender, CONCAT(P.FirstName,' ', P.LastName) as Name
  FROM 
 CTE INNER JOIN Person.Person P
  ON
 CTE.BusinessEntityID = P.BusinessEntityID
);

GO

select * from GetMaritalStatusByGender('F');
Copy
Resultado

MaritalStatus

Gênero

Nome

S

F

Terri Duffy

M

F

Gail Erickson

S

F

Diane Margheim

M

F

Gigi Matthew

M

F

Janice Galvin

M

F

Sharon Salavaria

S

F

Mary Dempsey

M

F

Wanida Benshoof

M

F

Mary Gibson

M

F

Jill Williams

S

F

Jo Brown

M

F

Britta Simon

M

F

Margie Shoop

M

F

Rebecca Laszlo

M

F

Suchitra Mohan

M

F

Kim Abercrombie

S

F

JoLynn Dobney

M

F

Nancy Anderson

M

F

Ruth Ellerbrock

M

F

Doris Hartwig

M

F

Diane Glimp

M

F

Bonnie Kearney

M

F

Denise Smith

S

F

Diane Tibbott

M

F

Carole Poland

M

F

Carol Philips

M

F

Merav Netz

S

F

Betsy Stadick

S

F

Danielle Tiedt

S

F

Kimberly Zimmerman

M

F

Elizabeth Keyser

M

F

Mary Baker

M

F

Alice Ciccu

M

F

Linda Moschell

S

F

Angela Barbariol

S

F

Kitti Lertpiriyasuwat

S

F

Susan Eaton

S

F

Kim Ralls

M

F

Nicole Holliday

S

F

Anibal Sousa

M

F

Samantha Smith

S

F

Olinda Turner

S

F

Cynthia Randall

M

F

Sandra Reátegui Alayo

S

F

Linda Randall

S

F

Shelley Dyck

S

F

Laura Steele

S

F

Susan Metters

S

F

Katie McAskill-White

M

F

Barbara Decker

M

F

Yvonne McKay

S

F

Janeth Esteves

M

F

Brenda Diaz

M

F

Lorraine Nay

M

F

Paula Nartker

S

F

Lori Kane

M

F

Kathie Flood

S

F

Belinda Newman

M

F

Karen Berge

M

F

Lori Penor

M

F

Jo Berry

M

F

Laura Norman

M

F

Paula Barreto de Mattos

M

F

Mindy Martin

M

F

Deborah Poe

S

F

Candy Spoon

M

F

Barbara Moreland

M

F

Janet Sheperdigian

S

F

Wendy Kahn

S

F

Sheela Word

M

F

Linda Meisner

S

F

Erin Hagens

M

F

Annette Hill

S

F

Jean Trenary

S

F

Stephanie Conroy

S

F

Karen Berg

M

F

Janaina Bueno

M

F

Linda Mitchell

S

F

Jillian Carson

S

F

Pamela Ansman-Wolfe

S

F

Lynn Tsoflias

M

F

Amy Alberts

S

F

Rachel Valdez

M

F

Jae Pak

Snowflake SQL
com valor de tabela inline
 --** SSC-FDM-0007 - MISSING DEPENDENT OBJECTS "HumanResources.Employee", "Person.Person" **
CREATE OR REPLACE FUNCTION GetMaritalStatusByGender
(P_GENDER STRING
)
RETURNS TABLE(
 MaritalStatus STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN MaritalStatus WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
 Gender STRING /*** SSC-FDM-TS0012 - INFORMATION FOR THE COLUMN Gender WAS NOT FOUND. STRING DATATYPE USED TO MATCH CAST AS STRING OPERATION ***/,
 Name VARCHAR
)
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "07/11/2025",  "domain": "no-domain-provided" }}'
AS
$$
 --** SSC-PRF-TS0001 - PERFORMANCE WARNING - RECURSION FOR CTE NOT CHECKED. MIGHT REQUIRE RECURSIVE KEYWORD **
  WITH CTE AS
 (
  SELECT
   BusinessEntityID,
   MaritalStatus,
   Gender
  FROM
   HumanResources.Employee
  where
   Gender = :P_GENDER
 )
  SELECT
  CAST(MaritalStatus AS STRING),
  CAST(Gender AS STRING),
  CONCAT(P.FirstName,' ', P.LastName) as Name
  FROM
  CTE
  INNER JOIN
   Person.Person P
  ON CTE.BusinessEntityID = P.BusinessEntityID
$$;

select
  *
from
  TABLE(GetMaritalStatusByGender('F'));
Copy
Resultado

MaritalStatus

Gênero

Nome

S

F

Terri Duffy

M

F

Gail Erickson

S

F

Diane Margheim

M

F

Gigi Matthew

M

F

Janice Galvin

M

F

Sharon Salavaria

S

F

Mary Dempsey

M

F

Wanida Benshoof

M

F

Mary Gibson

M

F

Jill Williams

S

F

Jo Brown

M

F

Britta Simon

M

F

Margie Shoop

M

F

Rebecca Laszlo

M

F

Suchitra Mohan

M

F

Kim Abercrombie

S

F

JoLynn Dobney

M

F

Nancy Anderson

M

F

Ruth Ellerbrock

M

F

Doris Hartwig

M

F

Diane Glimp

M

F

Bonnie Kearney

M

F

Denise Smith

S

F

Diane Tibbott

M

F

Carole Poland

M

F

Carol Philips

M

F

Merav Netz

S

F

Betsy Stadick

S

F

Danielle Tiedt

S

F

Kimberly Zimmerman

M

F

Elizabeth Keyser

M

F

Mary Baker

M

F

Alice Ciccu

M

F

Linda Moschell

S

F

Angela Barbariol

S

F

Kitti Lertpiriyasuwat

S

F

Susan Eaton

S

F

Kim Ralls

M

F

Nicole Holliday

S

F

Anibal Sousa

M

F

Samantha Smith

S

F

Olinda Turner

S

F

Cynthia Randall

M

F

Sandra Reátegui Alayo

S

F

Linda Randall

S

F

Shelley Dyck

S

F

Laura Steele

S

F

Susan Metters

S

F

Katie McAskill-White

M

F

Barbara Decker

M

F

Yvonne McKay

S

F

Janeth Esteves

M

F

Brenda Diaz

M

F

Lorraine Nay

M

F

Paula Nartker

S

F

Lori Kane

M

F

Kathie Flood

S

F

Belinda Newman

M

F

Karen Berge

M

F

Lori Penor

M

F

Jo Berry

M

F

Laura Norman

M

F

Paula Barreto de Mattos

M

F

Mindy Martin

M

F

Deborah Poe

S

F

Candy Spoon

M

F

Barbara Moreland

M

F

Janet Sheperdigian

S

F

Wendy Kahn

S

F

Sheela Word

M

F

Linda Meisner

S

F

Erin Hagens

M

F

Annette Hill

S

F

Jean Trenary

S

F

Stephanie Conroy

S

F

Karen Berg

M

F

Janaina Bueno

M

F

Linda Mitchell

S

F

Jillian Carson

S

F

Pamela Ansman-Wolfe

S

F

Lynn Tsoflias

M

F

Amy Alberts

S

F

Rachel Valdez

M

F

Jae Pak

Problemas conhecidos

Não foram encontrados problemas

MULTI-STATEMENT TABLE-VALUED

Referência de tradução para converter UDF (funções definidas pelo usuário) do Transact-SQL com o tipo de retorno TABLE em Snowflake.

Applies to
  • SQL Server

  • Azure Synapse Analytics

Nota

Algumas partes do código de saída foram omitidas por motivos de clareza.

Nota

Todos os exemplos de código nesta página ainda não foram implementados no SnowConvert AI. Eles devem ser interpretados como uma referência de como cada cenário deve ser traduzido para o Snowflake. Essas traduções podem mudar no futuro. Algumas partes no código de saída são omitidas por questão de clareza.

Descrição

O valor de tabela com várias instruções é semelhante ao valor de tabela com instrução inline (INLINE TABLE-VALUED). Embora o valor de tabela com várias instruções possa ter mais de uma instrução no corpo da função, as colunas da tabela são especificadas no tipo de retorno e ela possui um bloco BEGIN/END (Referência da linguagem SQL Server, Criando uma função com valor de tabela com várias instruções

Sintaxe do Transact-SQL

CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ] [ type_schema_name. ] parameter_data_type
    [ = default ] [READONLY] }
    [ ,...n ]
  ]
)
RETURNS @return_variable TABLE <table_type_definition>
    [ WITH <function_option> [ ,...n ] ]
    [ AS ]
    BEGIN
        function_body
        RETURN
    END
[ ; ]
Copy

Snowflake SQL

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

Amostra de padrões da origem

A seção a seguir descreve todos os possíveis padrões de código-fonte que podem aparecer nesse tipo de sintaxe ofCREATE FUNCTION.

O corpo da função Multi-Statement Table-Valued deve ser uma instrução SELECT. Por esse motivo, as outras instruções devem ser chamadas separadamente.

Inserir valores em uma tabela

Insere uma ou mais linhas na tabela e retorna a tabela com os novos valores

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
CREATE OR ALTER FUNCTION calc_behavioral_segment()
RETURNS @behavioral_segments TABLE (behavioral_segment VARCHAR(50))
AS
BEGIN
 DECLARE @col varchar(15)
 SET @col = 'Unknown'
 INSERT INTO @behavioral_segments 
 SELECT @col
 
 RETURN 
END

SELECT * FROM calc_behavioral_segment();
Copy
Resultado

BEHAVIORAL_SEGMENT

Desconhecido

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION calc_behavioral_segment ()
RETURNS BEHAVIORAL_SEGMENTS TABLE (
 behavioral_segment VARCHAR(50))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
 DECLARE @col varchar(15)
 SET @col = 'Unknown'
 INSERT INTO @behavioral_segments
 SELECT @col

 RETURN
END

SELECT * FROM calc_behavioral_segment();;
Copy
Resultados

BEHAVIORAL_SEGMENT

Desconhecido

Inserir valor de acordo com a instrução if/else

Insere uma linha na tabela de acordo com a condição e retorna a tabela com o novo valor

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
CREATE OR ALTER FUNCTION odd_or_even_number(@number INT)
RETURNS @numbers TABLE (number_type VARCHAR(15))
AS
BEGIN 
 IF ((@number % 2) = 0)
 BEGIN
  INSERT @numbers SELECT 'Even'
 END
    
 ELSE
 BEGIN
  INSERT @numbers SELECT 'Odd'
 END

 RETURN
END

SELECT * FROM odd_or_even_number(9);
Copy
Resultado

NUMBER_TYPE

ímpar

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION odd_or_even_number (NUMBER INT)
RETURNS NUMBERS TABLE (
 number_type VARCHAR(15))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
 IF ((@number % 2) = 0)
 BEGIN
  INSERT @numbers SELECT 'Even'
 END

 ELSE
 BEGIN
  INSERT @numbers SELECT 'Odd'
 END

 RETURN
END

SELECT * FROM odd_or_even_number(9);;
Copy
Resultado

NUMBER_TYPE

ímpar

Insere múltiplos de acordo com a instrução if/else

O exemplo abaixo insere mais de um valor na tabela e mais de uma variável é modificada de acordo com a condição. Retorna a tabela com os novos valores

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
CREATE OR ALTER FUNCTION new_employee_hired(@id VARCHAR (50), @position VARCHAR(50), @experience VARCHAR(15))
RETURNS @new_employee TABLE (id_employee VARCHAR (50), working_from_home BIT, team VARCHAR(15), computer VARCHAR(15)) 
AS
BEGIN 
 DECLARE @wfh BIT
 DECLARE @team VARCHAR(15)
 DECLARE @computer VARCHAR(15)

 IF @position = 'DEVELOPER'
 BEGIN
  SET @team = 'TEAM_1'
  SET @computer = 'LAPTOP'  
 END

 IF @position = 'IT'
 BEGIN  
  SET @team = 'TEAM_2'
  SET @computer = 'DESKTOP'
 END

 IF @experience = 'JUNIOR'
 BEGIN
  SET @wfh = '0'   
 END
 IF @experience = 'SENIOR'
 BEGIN
  SET @wfh = '1'      
 END

 INSERT INTO @new_employee VALUES (@id, @wfh, @team, @computer)
 RETURN
END

SELECT * FROM new_employee_hired('123456789', 'DEVELOPER', 'SENIOR');
Copy
Resultado

ID_EMPLOYEE

WORKING_FROM_HOME

TEAM

COMPUTER

123456789

1

TEAM_1

LAPTOP

Snowflake
MULTI-STATEMENT TABLE-VALUED
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION new_employee_hired (ID STRING, POSITION STRING, EXPERIENCE STRING)
RETURNS NEW_EMPLOYEE TABLE (
 id_employee VARCHAR(50),
 working_from_home BOOLEAN,
 team VARCHAR(15),
 computer VARCHAR(15))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
 DECLARE @wfh BIT
 DECLARE @team VARCHAR(15)
 DECLARE @computer VARCHAR(15)

 IF @position = 'DEVELOPER'
 BEGIN
  SET @team = 'TEAM_1'
  SET @computer = 'LAPTOP'
 END

 IF @position = 'IT'
 BEGIN
  SET @team = 'TEAM_2'
  SET @computer = 'DESKTOP'
 END

 IF @experience = 'JUNIOR'
 BEGIN
  SET @wfh = '0'
 END
 IF @experience = 'SENIOR'
 BEGIN
  SET @wfh = '1'
 END

 INSERT INTO @new_employee VALUES (@id, @wfh, @team, @computer)
 RETURN
END

SELECT * FROM new_employee_hired('123456789', 'DEVELOPER', 'SENIOR');;
Copy
Resultado

ID_EMPLOYEE

WORKING_FROM_HOME

TEAM

COMPUTER

123456789

1

TEAM_1

LAPTOP

Aviso

Se houver instruções if aninhadas e mais de uma variável for modificada nas instruções, será necessário usar um procedimento armazenado.

Atualizar valores inseridos anteriormente

Atualiza os valores das colunas da tabela no corpo da função e o retorna com os novos valores.

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
CREATE OR ALTER FUNCTION get_employees_history()
RETURNS @employee_history TABLE (
 department_name NVARCHAR(50),
 first_name NVARCHAR(50),
 last_name NVARCHAR(50), 
 start_date DATE,
 end_date DATE,
 job_title NVARCHAR(50), 
 months_working INT
)
BEGIN
 INSERT INTO @employee_history
 SELECT D.name AS department_name, P.first_name, P.last_name, EH.start_date, EH.end_date, E.job_title, 0 FROM Department D
 LEFT OUTER JOIN employee_department_history EH
  ON D.department_ID = EH.department_ID
 INNER JOIN  Employee E
  ON E.business_entity_ID = EH.business_entity_ID
 INNER JOIN Person P
  ON P.business_entity_ID = E.business_entity_ID 
  

 UPDATE @employee_history
 SET 
  months_working = 
  CASE WHEN end_date IS NULL THEN DATEDIFF(MONTH, start_date, GETDATE())
  ELSE DATEDIFF(MONTH, start_date, end_date)
 END
 RETURN;
END;

SELECT TOP(10) * FROM get_employees_history();
Copy
Resultado

DEPARTMENT_NAME

FIRST_NAME

LAST_NAME

START_DATE

END_DATE

JOB_TITLE

MONTHS_WORKING

Vendas

Syed

Abbas

2013-03-14

NULL

Gerente de vendas do Pacífico

106

Produção

Kim

Abercrombie

2010-01-16

NULL

Técnica de produção - WC60

144

Garantia de Qualidade

Hazem

Abolrous

2009-02-28

NULL

Gerente de garantia de qualidade

155

Expedição e recebimento

Pilar

Ackerman

2009-01-02

NULL

Supervisor de envio e recebimento

156

Produção

Jay

Adams

2009-03-05

NULL

Técnica de produção - WC60

154

Serviços de informação

François

Ajenstat

2009-01-17

NULL

Administrador de banco de dados

156

Vendas

Amy

Alberts

2012-04-16

NULL

Gerente de vendas da Europa

117

Produção

Greg

Alderson

2008-12-02

NULL

Técnica de produção - WC45

157

Garantia de Qualidade

Sean

Alexander

2008-12-28

NULL

Técnico de garantia de qualidade

157

Instalações e manutenção

Gary

Altman

2009-12-02

NULL

Gerente de instalações

145

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION get_employees_history ()
RETURNS EMPLOYEE_HISTORY TABLE (
 department_name VARCHAR(50),
 first_name VARCHAR(50),
 last_name VARCHAR(50),
 start_date DATE,
 end_date DATE,
 job_title VARCHAR(50),
 months_working INT
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
BEGIN
 INSERT INTO @employee_history
 SELECT D.name AS department_name, P.first_name, P.last_name, EH.start_date, EH.end_date, E.job_title, 0 FROM Department D
 LEFT OUTER JOIN employee_department_history EH
  ON D.department_ID = EH.department_ID
 INNER JOIN  Employee E
  ON E.business_entity_ID = EH.business_entity_ID
 INNER JOIN Person P
  ON P.business_entity_ID = E.business_entity_ID


 UPDATE @employee_history
 SET
  months_working =
  CASE WHEN end_date IS NULL THEN DATEDIFF(MONTH, start_date, GETDATE())
  ELSE DATEDIFF(MONTH, start_date, end_date)
 END
 RETURN;
END;

SELECT TOP(10) * FROM get_employees_history();;
Copy
Resultado

DEPARTMENT_NAME

FIRST_NAME

LAST_NAME

START_DATE

END_DATE

JOB_TITLE

MONTHS_WORKING

Vendas

Syed

Abbas

2013-03-14

NULL

Gerente de vendas do Pacífico

106

Produção

Kim

Abercrombie

2010-01-16

NULL

Técnica de produção - WC60

144

Garantia de Qualidade

Hazem

Abolrous

2009-02-28

NULL

Gerente de garantia de qualidade

155

Expedição e recebimento

Pilar

Ackerman

2009-01-02

NULL

Supervisor de envio e recebimento

156

Produção

Jay

Adams

2009-03-05

NULL

Técnica de produção - WC60

154

Serviços de informação

François

Ajenstat

2009-01-17

NULL

Administrador de banco de dados

156

Vendas

Amy

Alberts

2012-04-16

NULL

Gerente de vendas da Europa

117

Produção

Greg

Alderson

2008-12-02

NULL

Técnica de produção - WC45

157

Garantia de Qualidade

Sean

Alexander

2008-12-28

NULL

Técnico de garantia de qualidade

157

Instalações e manutenção

Gary

Altman

2009-12-02

NULL

Gerente de instalações

145

Múltiplas cláusulas de retorno

No exemplo a seguir, há mais de uma cláusula de retorno, porque, dependendo da situação, não é necessário continuar executando a função inteira.

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
CREATE OR ALTER FUNCTIONcreate_new_team(@team_name VARCHAR(50))
</strong>RETURNS @new_team TABLE (type VARCHAR(50), name VARCHAR(50))
AS
BEGIN
 DECLARE @employees INT
 SET @employees = (SELECT count(*) FROM employee)
 DECLARE @type VARCHAR(15)
 SET @type = 'small_team'
 IF (@employees &#x3C; 8)
 BEGIN
  INSERT @new_team VALUES (@type, @team_name)
  RETURN
 END

 SET @type = 'big_team'
 INSERT @new_team VALUES (@type, @team_name)

 RETURN
END

SELECT * FROMcreate_new_team('Team1');
Copy
Resultado

TYPE

NAME

SMALL_TEAM

TEAM1

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTIONcreate_new_team (TEAM_NAME STRING)
RETURNS NEW_TEAM TABLE (
 type VARCHAR(50),
 name VARCHAR(50))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
 DECLARE @employees INT
 SET @employees = (SELECT count(*) FROM employee)
 DECLARE @type VARCHAR(15)
 SET @type = 'small_team'
 IF (@employees < 8)
 BEGIN
  INSERT @new_team VALUES (@type, @team_name)
  RETURN
 END

 SET @type = 'big_team'
 INSERT @new_team VALUES (@type, @team_name)

 RETURN
END

SELECT * FROMcreate_new_team('Team1');;
Copy
Resultado

TYPE

NAME

SMALL_TEAM

TEAM1

Aviso

Essa transformação é aplicada quando há apenas um valor a ser inserido; se houver mais de um valor, será necessário usar um procedimento armazenado.

Casos complexos

O exemplo é um caso complexo que usa instruções aninhadas if e insere um valor dependendo da condição verdadeira.

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
CREATE OR ALTER FUNCTION vacation_status(@id VARCHAR (50))
RETURNS @status TABLE (vacation_status VARCHAR(30))
AS
BEGIN 
 DECLARE @hire_date DATETIME
 SET @hire_date = (SELECT @hire_date FROM employee WHERE employeeId = @id)
 DECLARE @vacation_hours INT
 SET @vacation_hours = (SELECT count(vacation_hours) FROM employee WHERE employeeId = @id)
 DECLARE @time_working INT
 SET @time_working = (SELECT DATEDIFF(MONTH, @hire_date,GETDATE()))

 IF (@vacation_hours > 0)
 BEGIN
  IF (@time_working > 3)
  BEGIN
   IF (@vacation_hours < 120)
   BEGIN
    INSERT INTO @status VALUES ('Ok')
   END

   IF (@vacation_hours = 120)
   BEGIN
    INSERT INTO @status values ('In the limit')
   END

   IF (@vacation_hours > 120)
   BEGIN
    INSERT INTO @status VALUES ('With excess')
   END
  END
  ELSE
  BEGIN
   INSERT INTO @status values ('Hired recently')
  END
 END
 ELSE
 BEGIN
  INSERT INTO @status values ('No hours')
 END
 RETURN
END

SELECT * FROM vacation_status('adventure-worksken0')
Copy
Resultado

VACATION_STATUS

OK

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION vacation_status (ID STRING)
RETURNS STATUS TABLE (
 vacation_status VARCHAR(30))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
 DECLARE @hire_date DATETIME
 SET @hire_date = (SELECT @hire_date FROM employee WHERE employeeId = @id)
 DECLARE @vacation_hours INT
 SET @vacation_hours = (SELECT count(vacation_hours) FROM employee WHERE employeeId = @id)
 DECLARE @time_working INT
 SET @time_working = (SELECT DATEDIFF(MONTH, @hire_date,GETDATE()))

 IF (@vacation_hours > 0)
 BEGIN
  IF (@time_working > 3)
  BEGIN
   IF (@vacation_hours < 120)
   BEGIN
    INSERT INTO @status VALUES ('Ok')
   END

   IF (@vacation_hours = 120)
   BEGIN
    INSERT INTO @status values ('In the limit')
   END

   IF (@vacation_hours > 120)
   BEGIN
    INSERT INTO @status VALUES ('With excess')
   END
  END
  ELSE
  BEGIN
   INSERT INTO @status values ('Hired recently')
  END
 END
 ELSE
 BEGIN
  INSERT INTO @status values ('No hours')
 END
 RETURN
END

SELECT * FROM vacation_status('adventure-worksken0');
Copy
Segunda guia

VACATION_STATUS

OK

Problemas conhecidos

Instruções while ao lado de consultas

O problema com esse exemplo é que não há como transformar a instrução while em CTE dentro da cláusula WITH do Select principal, o que nos força a transformar essa instrução em procedimento armazenado para manter a mesma lógica.

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
--Additional Params: -t JavaScript
CREATE OR ALTER FUNCTION get_group_name
(@department_id INT)
RETURNS @group_names TABLE (group_name VARCHAR(15))
AS
BEGIN
DECLARE @name VARCHAR(30) = 'Another Department'  
WHILE @name = 'Another Department'
BEGIN
 IF (@department_id &#x3C; 3)
 BEGIN
  SET @name = 'engineering'
 END

 IF @department_id = 3
 BEGIN
  SET @name = 'Tool Design'
 END

 SELECT @department_id = @department_id / 3
END
INSERT @group_names SELECT @name
RETURN
END

SELECT * FROM get_group_name(9);
Copy
Resultado

GROUP_NAME

Projeto de ferramentas

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
 !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!
CREATE OR ALTER FUNCTION get_group_name
(DEPARTMENT_ID INT)
RETURNS @group_names TABLE (
 group_name VARCHAR(15))
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
DECLARE @name VARCHAR(30) = 'Another Department'
WHILE @name = 'Another Department'
BEGIN
 IF (@department_id < 3)
 BEGIN
  SET @name = 'engineering'
 END

 IF @department_id = 3
 BEGIN
  SET @name = 'Tool Design'
 END

 SELECT @department_id = @department_id / 3
END
INSERT @group_names SELECT @name
RETURN
END

SELECT * FROM get_group_name(9);;
Copy
Resultado

GROUP_NAME

Projeto de ferramentas

Declare Cursor

As funções definidas pelo usuário não podem DECLARE, OPEN, FETCH, CLOSE ou DEALLOCATE um CURSOR. Use um procedimento armazenado para trabalhar com cursores.

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
 --Additional Params: -t JavaScript

CREATE OR ALTER FUNCTION amount_new_specimens(@id int)
RETURNS @new_specimens TABLE (amount int)
AS
BEGIN
 DECLARE @first_specimen VARCHAR(30) ;
 set @first_specimen = (select name_specimen from specimen where specimen_id = @id);
 DECLARE @second_specimen VARCHAR(30);

 DECLARE @specimens TABLE (name_specimen VARCHAR(30))

 DECLARE Cursor1 CURSOR 
 FOR SELECT name_specimen 
 FROM specimen 

 OPEN cursor1
 FETCH NEXT FROM cursor1
 INTO @second_specimen;
 
 WHILE @@FETCH_STATUS = 0 
 BEGIN
  IF @first_specimen <> @second_specimen
  BEGIN
   INSERT INTO @specimens values (CONCAT_WS('-', @first_specimen, @second_specimen))
  END
  FETCH NEXT FROM cursor1
  INTO @second_specimen;
 END

 CLOSE cursor1;
 DEALLOCATE cursor1;

 INSERT INTO @new_specimens SELECT COUNT(*) FROM @specimens
 RETURN 
END

SELECT * FROM amount_new_specimens(1);
Copy
Resultado

AMOUNT

3

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
 --Additional Params: -t JavaScript
!!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'TABLE VALUED FUNCTIONS' NODE ***/!!!

CREATE OR ALTER FUNCTION amount_new_specimens (ID INT)
RETURNS @new_specimens TABLE (
 amount INT
)
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
BEGIN
 DECLARE @first_specimen VARCHAR(30) ;
 set @first_specimen = (select name_specimen from specimen where specimen_id = @id);
 DECLARE @second_specimen VARCHAR(30);

 DECLARE @specimens TABLE (name_specimen VARCHAR(30))

 DECLARE Cursor1 CURSOR
 FOR SELECT name_specimen
 FROM specimen

 OPEN cursor1
 FETCH NEXT FROM cursor1
 INTO @second_specimen;

 WHILE @@FETCH_STATUS = 0
 BEGIN
  IF @first_specimen <> @second_specimen
  BEGIN
   INSERT INTO @specimens values (CONCAT_WS('-', @first_specimen, @second_specimen))
  END
  FETCH NEXT FROM cursor1
  INTO @second_specimen;
 END

 CLOSE cursor1;
 DEALLOCATE cursor1;

 INSERT INTO @new_specimens SELECT COUNT(*) FROM @specimens
 RETURN
END

SELECT * FROM amount_new_specimens(1);;
Copy
Resultado

AMOUNT

3

Não há suporte para instruções diferentes em Expressões de tabela comuns

As cláusulas UPDATE, INSERT, DELETE, ALTER ou DROP não são compatíveis com o corpo de expressões de tabela comuns, mesmo após sua declaração usando um delimitador. Por esse motivo, a função pode ser modificada para funcionar como um procedimento armazenado.

Transact-SQL
MULTI-STATEMENT TABLE-VALUED
 --Additional Params: -t JavaScript

CREATE OR ALTER PROCEDURE product_history 
AS
BEGIN
 DECLARE @product_history TABLE (
  product_name NVARCHAR(50),
  rating INT
 )
 INSERT INTO @product_history
 SELECT P.Name AS product_name, AVG(ALL R.rating) FROM Production.product P
 INNER JOIN  Production.product_review R
  ON R.product_ID = P.product_ID
 GROUP BY P.Name;

 DELETE FROM @product_history
 WHERE rating < 2;

 SELECT * FROM @product_history; 

END
GO;

EXEC product_history
Copy
Resultado

PRODUCT_NAME

Classificação

HL Mountain Pedal

3

Mountain Bike Socks, M

5

Road-550-W Yellow, 40

5

Snowflake SQL
MULTI-STATEMENT TABLE-VALUED
CREATE OR REPLACE PROCEDURE product_history ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
 // REGION SnowConvert AI Helpers Code
 var _RS, ROW_COUNT, _ROWS, MESSAGE_TEXT, SQLCODE = 0, SQLSTATE = '00000', OBJECT_SCHEMA_NAME  = 'UNKNOWN', ERROR_HANDLERS, NUM_ROWS_AFFECTED, PROC_NAME = arguments.callee.name, DOLLAR_DOLLAR = '$' + '$';
 function* sqlsplit(sql) {
  var part = '';
  var ismark = () => sql[i] == '$' && sql[i + 1] == '$';
  for(var i = 0;i < sql.length;i++) {
   if (sql[i] == ';') {
    yield part + sql[i];
    part = '';
   } else if (ismark()) {
    part += sql[i++] + sql[i++];
    while ( i < sql.length && !ismark() ) {
     part += sql[i++];
    }
    part += sql[i] + sql[i++];
   } else part += sql[i];
  }
  if (part.trim().length) yield part;
 };
 var formatDate = (arg) => (new Date(arg - (arg.getTimezoneOffset() * 60000))).toISOString().slice(0,-1);
 var fixBind = function (arg) {
  arg = arg == undefined ? null : arg instanceof Date ? formatDate(arg) : arg;
  return arg;
 };
 var EXEC = (stmt,binds = [],severity = "16",noCatch = false) => {
  binds = binds ? binds.map(fixBind) : binds;
  for(var stmt of sqlsplit(stmt)) {
   try {
    _RS = snowflake.createStatement({
      sqlText : stmt,
      binds : binds
     });
    _ROWS = _RS.execute();
    ROW_COUNT = _RS.getRowCount();
    NUM_ROWS_AFFECTED = _RS.getNumRowsAffected();
    return {
     THEN : (action) => !SQLCODE && action(fetch(_ROWS))
    };
   } catch(error) {
    let rStack = new RegExp('At .*, line (\\d+) position (\\d+)');
    let stackLine = error.stackTraceTxt.match(rStack) || [0,-1];
    MESSAGE_TEXT = error.message.toString();
    SQLCODE = error.code.toString();
    SQLSTATE = error.state.toString();
    snowflake.execute({
     sqlText : `SELECT UPDATE_ERROR_VARS_UDF(?,?,?,?,?,?)`,
     binds : [stackLine[1],SQLCODE,SQLSTATE,MESSAGE_TEXT,PROC_NAME,severity]
    });
    throw error;
   }
  }
 };
 // END REGION

  EXEC(`CREATE OR REPLACE TEMPORARY TABLE T_product_history (
   product_name VARCHAR(50),
   rating INT
)`);
 EXEC(` INSERT INTO T_product_history
 SELECT
    P.Name AS product_name,
    AVG(ALL R.rating) FROM
    Production.product P
    INNER JOIN
       Production.product_review R
       ON R.product_ID = P.product_ID
 GROUP BY
    P.Name`);
 EXEC(`DELETE FROM
   T_product_history
WHERE
   rating < 2`);
 EXEC(`
 SELECT
    *
 FROM
    T_product_history`);
$$;
;

CALL product_history();
Copy
Resultado

PRODUCT_NAME

Classificação

HL Mountain Pedal

3

Mountain Bike Socks, M

5

Road-550-W Yellow, 40

5

EWIs relacionados

  1. SSC-EWI-0040: Instrução incompatível.

  2. SSC-EWI-0073: Revisão de equivalência funcional pendente

SCALAR

Referência de tradução para converter UDF (funções definidas pelo usuário) do Transact-SQL com tipo de retorno escalar para o Snowflake.

Applies to
  • SQL Server

  • Azure Synapse Analytics

Descrição

Nota

Algumas partes do código de saída foram omitidas por motivos de clareza.

Uma função escalar definida pelo usuário é uma rotina Transact-SQL ou tempo de execução de linguagem comum (CLR) que aceita parâmetros, executa uma ação, como um cálculo complexo, e retorna o resultado dessa ação como um valor escalar. (Referência da linguagem SQL Server, subseção ReferenceCREATE FUNCTION).

Nota

Essas funções geralmente são usadas dentro da instrução SELECTou na configuração de uma única variável (provavelmente dentro de um procedimento armazenado).

Sintaxe do Transact-SQL

 -- Transact-SQL Scalar Function Syntax
CREATE [ OR ALTER ] FUNCTION [ schema_name. ] function_name
( [ { @parameter_name [ AS ][ type_schema_name. ] parameter_data_type
 [ = default ] [ READONLY ] }
    [ ,...n ]
  ]
)
RETURNS return_data_type
    [ WITH <function_option> [ ,...n ] ]
    [ AS ]
    BEGIN
        function_body
        RETURN scalar_expression
    END
[ ; ]
Copy

Sintaxe do Snowflake

O Snowflake permite 3 linguagens diferentes em suas funções definidas pelo usuário:

  • SQL

  • JavaScript

  • Java

Por enquanto, o SnowConvert AI será compatível somente com SQL e JavaScript como linguagens de destino.

SQL

Nota

Funções definidas pelo usuário do SQL suportam apenas uma consulta como seu corpo. Elas podem ler o banco de dados, mas não têm permissão para gravá-lo ou modificá-lo. (Referência Scalar SQL UDFs).

CREATE [ OR REPLACE ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'
Copy
JavaScript

Nota

Funções definidas pelo usuário do JavaScript permitem várias instruções em seus corpos, mas não podem realizar consultas ao banco de dados. (Referência Scalar JavaScriptUDFs)

CREATE [ OR REPLACE ] [ SECURE ] FUNCTION <name> ( [ <arg_name> <arg_data_type> ] [ , ... ] )
  RETURNS { <result_data_type> | TABLE ( <col_name> <col_data_type> [ , ... ] ) }
  [ [ NOT ] NULL ]
  LANGUAGE JAVASCRIPT
  [ { CALLED ON NULL INPUT | { RETURNS NULL ON NULL INPUT | STRICT } } ]
  [ VOLATILE | IMMUTABLE ]
  [ COMMENT = '<string_literal>' ]
  AS '<function_definition>'
Copy

Amostra de padrões da origem

Instruções Set e Declare

As instruções mais comuns nos corpos das funções são as instruções DECLARE e SET. Para instruções DECLARE sem valor padrão, a transformação será ignorada. As instruções SET e DECLARE com um valor padrão serão transformadas em COMMON TABLE EXPRESSION. Cada expressão de tabela comum conterá uma coluna que representa o valor da variável local.

Transact-SQL
Consulta
CREATE OR ALTER FUNCTION PURCHASING.GetVendorName()
RETURNS NVARCHAR(50) AS
BEGIN
 DECLARE @result NVARCHAR(50)
 DECLARE @BUSINESSENTITYID INT
 
 SET @BUSINESSENTITYID = 1492
 
 SELECT @result = Name FROM PURCHASING.VENDOR WHERE BUSINESSENTITYID = @BUSINESSENTITYID
 
 RETURN @result
END

GO

SELECT PURCHASING.GetVendorName() as vendor_name;
Copy
Resultado

vendor_name

Australia Bike Retailer

Snowflake
Consulta
CREATE OR REPLACE FUNCTION PURCHASING.GetVendorName ()
RETURNS VARCHAR(50)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
 WITH CTE1 AS
 (
  SELECT
   1492 AS BUSINESSENTITYID
 ),
 CTE2 AS
 (
  SELECT
   Name AS RESULT
  FROM
   PURCHASING.VENDOR
  WHERE
   BUSINESSENTITYID = (
    SELECT
     BUSINESSENTITYID
    FROM
     CTE1
   )
 )
 SELECT
  RESULT
 FROM
  CTE2
$$;

SELECT
 PURCHASING.GetVendorName() as vendor_name;
Copy
Resultado

VENDOR_NAME

Australia Bike Retailer

Transformação da instrução If/Else

As instruções If/Else podem ser tratadas de diferentes maneiras: elas podem ser transformadas em Javascript ou em SQL usando CASE EXPRESSION dentro de Select permitindo condicionais dentro de consultas, enquanto a transformação em Javascript é bastante simples, a instrução Case pode não ser tão óbvia à primeira vista.

Transact-SQL
Consulta
CREATE OR ALTER FUNCTION PURCHASING.HasActiveFlag(@BusinessEntityID int)
RETURNS VARCHAR(10) AS
BEGIN
 DECLARE @result VARCHAR(10)
 DECLARE @ActiveFlag BIT
 
 SELECT @ActiveFlag = ActiveFlag from PURCHASING.VENDOR v where v.BUSINESSENTITYID = @BusinessEntityID
 
 IF @ActiveFlag = 1
  SET @result = 'YES'
 ELSE IF @ActiveFlag = 0 
  SET @result = 'NO'
 
 RETURN @result
END

GO

SELECT PURCHASING.HasActiveFlag(1516) as has_active_flag;
Copy
Resultado

has_active_flag

NO

Snowflake
Consulta
CREATE OR REPLACE FUNCTION PURCHASING.HasActiveFlag (P_BUSINESSENTITYID INT)
RETURNS VARCHAR(10)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
 WITH CTE1 AS
 (

  SELECT
   ActiveFlag AS ACTIVEFLAG
  from
   PURCHASING.VENDOR v
  where
   v.BUSINESSENTITYID = P_BUSINESSENTITYID
 ),
 CTE2 AS
 (
  SELECT
   CASE
    WHEN (
     SELECT
      ACTIVEFLAG
     FROM
      CTE1
    ) = 1
     THEN 'YES'
    WHEN (
     SELECT
      ACTIVEFLAG
     FROM
      CTE1
    ) = 0
     THEN 'NO'
   END AS RESULT
 )
 SELECT
  RESULT
 FROM
  CTE2
$$;

SELECT
 PURCHASING.HasActiveFlag(1516) as has_active_flag;
Copy
Resultado

HAS_ACTIVE_FLAG

NO

Instruções aninhadas

Para instruções aninhadas, a programação estruturada está sendo transformada em uma única consulta. As instruções no controle de fluxo serão aninhadas em estruturas de tabela para preservar a ordem de execução.

Nota

CASE EXPRESSIONS só pode retornar um valor por instrução

Exemplo

Nota

O código a seguir em ambos os paradigmas de programação é funcionalmente equivalente.

Programação estruturada
 DECLARE @VendorId AS int;
DECLARE @AccountNumber AS VARCHAR(50);
SELECT @VendorId = poh.VendorID 
    FROM Purchasing.PurchaseOrderHeader poh
    WHERE PurchaseOrderID = 1
SELECT @AccountNumber = v.AccountNumber
    FROM Purchasing.Vendor v
    WHERE v.BusinessEntityID = @VendorId
Copy
SQL
 SELECT V.AccountNumber AccountNumber
FROM (SELECT poh.VendorID VendorId 
         FROM Purchasing.PurchaseOrderHeader poh
         WHERE PurchaseOrderID = 1
) T1, Purchasing.Vendor v
WHERE v.BusinessEntityID = T1.VendorId
Copy
Resultado

AccountNumber

LITWARE0001

Variáveis condicionais por meio de SELECTs

A definição e a atribuição de variáveis em instruções condicionais tendem a ser um pouco problemáticas, pois as referências à variável mais adiante no código precisariam saber onde a variável foi modificada pela última vez. Além disso, se a referência estiver dentro de outra instrução condicional, terá de haver algum tipo de redirecionamento que faça referência à atribuição conhecida anterior à variável.

Isso tudo é agravado pelo aninhamento e por consultas complexas presentes no código de entrada. É por isso que um EWI específico é adicionado quando esses padrões são encontrados.

No cenário a seguir, a primeira instrução IF pode ser transformada sem problemas, pois o conteúdo é bastante simples. A segunda e a terceira instruções IF estão comentadas porque não são compatíveis no momento, já que há instruções que não são atribuições de variáveis por meio de SELECT.

SQL Server
Consulta
CREATE or ALTER FUNCTION PURCHASING.SELECTINUDF (
    @param1 varchar(12)
)
RETURNS int
AS
BEGIN
    declare @var1 int;
    declare @var2 int;
    declare @var3 int;

    IF @param1 = 'first'
    BEGIN
        select @var1 = col1 + 10 from table1 WHERE id = 0;
        select @var2 = col1 + 20 from table1 WHERE id = 0;
        select @var3 = col1 + 30 from table1 WHERE id = 0;
    END

    IF @param1 = 'second'
    BEGIN
        declare @var4 int = 10;
        select @var1 = col1 + 40 from table1 WHERE id = 0;
        select @var2 = col1 + 40 from table1 WHERE id = 0;
    END

    IF @param1 = 'third'
    BEGIN
        select col1 from table1 where id = 0;
        select @var1 = col1 + 50 from table1 WHERE id = 0;
        select @var2 = col1 + 50 from table1 WHERE id = 0;
    END

    RETURN @var1
END

SELECT PURCHASING.SELECTINUDF('first') as result; -- Assuming table1.col1 is 0 when ID = 0
Copy
Resultado

RESULT

10

Snowflake
Consulta
CREATE OR REPLACE FUNCTION PURCHASING.SELECTINUDF (PARAM1 STRING)
RETURNS INT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
    WITH CTE1 AS
    (
        SELECT
            CASE
                WHEN PARAM1 = 'first'
                    THEN (SELECT
                        col1 + 10 AS VAR1 from
                        table1
                        WHERE
                        id = 0)
            END AS VAR1,
            CASE
                WHEN PARAM1 = 'first'
                        THEN (SELECT
                        col1 + 20 AS VAR2 from
                        table1
                        WHERE
                        id = 0)
            END AS VAR2,
            CASE
                WHEN PARAM1 = 'first'
                        THEN (SELECT
                        col1 + 30 AS VAR3 from
                        table1
                        WHERE
                        id = 0)
            END AS VAR3
    ),
    !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'IF STATEMENT' NODE ***/!!!
    CTE2 AS
    (
        /*    IF @param1 = 'second'
            BEGIN
                declare @var4 int = 10;
                select @var1 = col1 + 40 from table1 WHERE id = 0;
                select @var2 = col1 + 40 from table1 WHERE id = 0;
            END*/
        SELECT
            null
    ),
    !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'IF STATEMENT' NODE ***/!!!
    CTE3 AS
    (
        /*    IF @param1 = 'third'
            BEGIN
                select col1 from table1 where id = 0;
                select @var1 = col1 + 50 from table1 WHERE id = 0;
                select @var2 = col1 + 50 from table1 WHERE id = 0;
            END*/
        SELECT
            null
    ),
    CTE4 AS
    (

        SELECT
            PURCHASING.SELECTINUDF('first') as result
    )
    SELECT
        VAR1
    FROM
        CTE4
$$ -- Assuming table1.col1 is 0 when ID = 0
;
Copy
Resultado

RESULT

10

Atribuir e retornar uma variável

Nesse padrão simples, há uma declaração de variável e, em seguida, essa variável é definida usando uma instrução SELECT e, por fim, retornada. Isso será migrado para uma Expressão de tabela comum para manter o comportamento original.

SQL Server
Consulta
CREATE OR ALTER FUNCTION Purchasing.GetTotalFreight()
RETURNS MONEY AS
BEGIN
 DECLARE @Result MONEY
 SELECT @Result = ISNULL(SUM(t.Freight), 0) from Purchasing.PurchaseOrderHeader t
 return @Result
END

GO

select Purchasing.GetTotalFreight() as Result;
Copy
Resultado

Resultado

1583978.2263

Snowflake
Consulta
CREATE OR REPLACE FUNCTION Purchasing.GetTotalFreight ()
RETURNS NUMBER(38, 4)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
 WITH CTE1 AS
 (
  SELECT
   NVL(SUM(t.Freight), 0) AS RESULT from
   Purchasing.PurchaseOrderHeader t
 )
 SELECT
  RESULT
 FROM
  CTE1
$$;

select
 Purchasing.GetTotalFreight() as Result;
Copy
Resultado

RESULT

1583978.2263

Chamadas de funções múltiplas

Para esse padrão específico, não há consultas óbvias, mas há várias chamadas para várias funções que trabalham com a mesma variável e a retornam no final. Como o Snowflake só oferece suporte a consultas dentro de suas funções, a solução para esse bloco será adicioná-lo a um Select e aninhar as chamadas dentro dele, certificando-se de que o valor de retorno seja o mesmo que o da origem.

SQL Server
Consulta
CREATE OR ALTER FUNCTION PURCHASING.Foo
(
 @PARAM1 INT
)
RETURNS varchar(25)
AS
BEGIN
 DECLARE @filter INT = @PARAM1
 DECLARE @NAME VARCHAR(25) = (SELECT Name from Purchasing.Vendor v where BusinessEntityID = @filter) 
 SET @NAME = REPLACE(@NAME, 'Australia', 'USA')
 SET @NAME = REPLACE(@NAME, 'Bike', 'Car')
 RETURN @NAME
END

GO

SELECT PURCHASING.Foo(1492) AS Name;
Copy
Resultado

Nome

USA Car Retailer

Snowflake
Consulta
CREATE OR REPLACE FUNCTION PURCHASING.Foo (PARAM1 INT)
RETURNS VARCHAR(25)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
 WITH CTE1 AS
 (
  SELECT
   PARAM1 AS FILTER
 ),
 CTE2 AS
 (
  SELECT
   (SELECT
     Name
    from
     Purchasing.Vendor v
    where
     BusinessEntityID = (
      SELECT
       FILTER
      FROM
       CTE1
     )
   ) AS NAME
 ),
 CTE3 AS
 (
  SELECT
   REPLACE((
    SELECT
     NAME
    FROM
     CTE3
   ), 'Australia', 'USA') AS NAME
 ),
 CTE4 AS
 (
  SELECT
   REPLACE((
    SELECT
     NAME
    FROM
     CTE4
   ), 'Bike', 'Car') AS NAME
 )
 SELECT
  NAME
 FROM
  CTE4
$$;

SELECT
 PURCHASING.Foo(1492) AS Name;
Copy
Resultado

NAME

USA Car Retailer

Aumentar uma variável com base em várias condições IF e retornar seu valor

Para esse padrão, uma variável é modificada (aumentada, neste caso) usando várias condições IF. No início, um conjunto de variáveis é inicializado e usado para determinar se a variável de resultado deve ser aumentada ou não. Por fim, a variável de resultado é retornada.

SQL Server
Consulta
CREATE OR ALTER FUNCTION PURCHASING.FOO() 
RETURNS MONEY
AS
BEGIN
 declare @firstValue MONEY
 declare @secondValue MONEY
 declare @Result MONEY
 select  @Result = 0
 select  @firstValue = SubTotal from Purchasing.PurchaseOrderHeader where PurchaseOrderID = 1
 select  @secondValue = SubTotal from Purchasing.PurchaseOrderHeader where PurchaseOrderID = 2
 if @firstValue is not null
  select @Result = @Result + @firstValue
 if @secondValue is not null
  select @Result = @Result + @secondValue
 return @Result 
END

GO

SELECT PURCHASING.Foo() AS Result;
Copy
Resultado

Resultado

473.1415

Snowflake
Consulta
CREATE OR REPLACE FUNCTION PURCHASING.FOO ()
RETURNS NUMBER(38, 4)
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
 WITH CTE1 AS
 (
  select
   0 AS RESULT
 ),
 CTE2 AS
 (
  select
   SubTotal AS FIRSTVALUE
  from
   Purchasing.PurchaseOrderHeader
  where
   PurchaseOrderID = 1
 ),
 CTE3 AS
 (
  select
   SubTotal AS SECONDVALUE
  from
   Purchasing.PurchaseOrderHeader
  where
   PurchaseOrderID = 2
 ),
 CTE4 AS
 (
  SELECT
   CASE
    WHEN (
     SELECT
      FIRSTVALUE
     FROM
      CTE2
    ) is not null
     THEN (
     select
      (
       SELECT
        RESULT
       FROM
        CTE1
      ) + (
       SELECT
        FIRSTVALUE
       FROM
        CTE2
      ) AS RESULT)
   END AS RESULT
 ),
 CTE5 AS
 (
  SELECT
   CASE
    WHEN (
     SELECT
      SECONDVALUE
     FROM
      CTE3
    ) is not null
     THEN (
     select
      (
       SELECT
        RESULT
       FROM
        CTE1
      ) + (
       SELECT
        SECONDVALUE
       FROM
        CTE3
      ) AS RESULT)
    ELSE (SELECT
     RESULT
    FROM
     CTE4)
   END AS RESULT
 )
 SELECT
  RESULT
 FROM
  CTE5
$$;

SELECT
 PURCHASING.Foo() AS Result;
Copy
Resultado

RESULT

473.1415

Duas ou mais instruções RETURN

Para esse padrão, o bloco IF que contém a cláusula de retorno que interrompe o fluxo do código é adicionado ao final do corpo, como a instrução final a ser executada em uma expressão CASE.

Case básico

Para esse cenário específico, não há lógica entre a instrução condicional RETURN e a instrução final RETURN, portanto, todo o corpo será mapeado para um único CASE EXPRESSION.

SQL Server
Consulta
CREATE OR ALTER FUNCTION [PURCHASING].[FOO] ()
RETURNS INT
AS
BEGIN
 IF exists (SELECT PreferredVendorStatus FROM Purchasing.Vendor v )
  RETURN 1

 RETURN 0
END

GO

SELECT PURCHASING.FOO() as result;
Copy
Resultado

resultado

1

Snowflake
Consulta
CREATE OR REPLACE FUNCTION PURCHASING.FOO ()
RETURNS INT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
 SELECT
  CASE
   WHEN exists (SELECT
     PreferredVendorStatus
    FROM
     Purchasing.Vendor v
   )
    THEN 1
   ELSE 0
  END
$$;

SELECT
 PURCHASING.FOO() as result;
Copy
Resultado

RESULT

1

Expressões de tabela comuns

As expressões de tabela comuns serão mantidas como no código original e serão concatenadas com as geradas. O SnowConvert AI é capaz de identificar primeiro todos os nomes COMMON TABLE EXPRESSION originais para evitar gerar nomes duplicados.

SQL Server
Consulta
CREATE OR ALTER FUNCTION [PURCHASING].[FOO] 
(
 @status INT
) 
Returns INT
As
Begin 
 Declare @result as int = 0

 ;WITH ctetable(RevisionNumber) as 
 (
  SELECT RevisionNumber
  FROM Purchasing.PurchaseOrderHeader poh
  where poh.Status = @status
 ),
 finalCte As
 (
  SELECT RevisionNumber FROM ctetable 
 )
 
 Select @result = count(RevisionNumber) from finalCte 
 return @result;
End

GO

SELECT PURCHASING.FOO(4) as result;
Copy
Resultado

resultado

3689

Snowflake
Consulta
CREATE OR REPLACE FUNCTION PURCHASING.FOO (STATUS INT)
Returns INT
LANGUAGE SQL
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},"attributes":{"component":"transact"}}'
AS
$$
 WITH CTE1 AS
 (
  SELECT
   0 AS RESULT
 ),
 ctetable (
  RevisionNumber
 ) as
  (
   SELECT
   RevisionNumber
   FROM
   Purchasing.PurchaseOrderHeader poh
   where
   poh.Status = STATUS
  ),
  finalCte As
  (
   SELECT
   RevisionNumber
  FROM
   ctetable
  ),
  CTE2 AS
  (
  Select
   COUNT(RevisionNumber) AS RESULT from
   finalCte
  )
  SELECT
  RESULT
  FROM
  CTE2
$$;

SELECT
  PURCHASING.FOO(4) as result;
Copy
Resultado

RESULT

3689

Transformar em JavaScript UDFs

Se houver várias instruções e a função não acessar o banco de dados de forma alguma, ela poderá ser transformada em uma função JavaScript mantendo a equivalência funcional

SQL Server
Consulta 1
CREATE OR ALTER FUNCTION PURCHASING.GetFiscalYear 
(
 @DATE AS DATETIME
)
RETURNS INT
AS
BEGIN
 DECLARE @FiscalYear AS INT
 DECLARE @CurMonth AS INT
 SET @CurMonth = DATEPART(M,@DATE)
 SET @FiscalYear = DATEPART(YYYY, @DATE)
 IF (@CurMonth >= 7)
 BEGIN
  SET @FiscalYear = @FiscalYear + 1 
 END
 RETURN @FiscalYear
END

GO

SELECT PURCHASING.GetFiscalYear('2020-10-10') as DATE;
Copy
Consulta 2
CREATE OR ALTER FUNCTION PURCHASING.[getCleanChargeCode]
(
 @ChargeCode varchar(50)
)
returns varchar(50) as
begin
 declare @CleanChargeCode varchar(50),@Len int,@Pos int=2
 set @Pos=LEN(@ChargeCode)-1
 while @Pos > 1
 begin
  set @CleanChargeCode=RIGHT(@ChargeCode,@Pos)
  if TRY_CAST(@CleanChargeCode as bigint) is not null
   return @CleanChargeCode
  set @Pos=@Pos-1
 end
 set @Pos=LEN(@ChargeCode)-1
 while @Pos > 1
 begin
  set @CleanChargeCode=LEFT(@ChargeCode,@Pos)
  if TRY_CAST(@CleanChargeCode as bigint) is not null
   return @CleanChargeCode
  set @Pos=@Pos-1
 end
 return null
end

GO

SELECT PURCHASING.[getCleanChargeCode]('16test') AS CleanChargeCode;
Copy
Resultado 1

DATE

2021

Resultado 2

CleanChargeCode

16

Snowflake
Consulta 1
!!!RESOLVE EWI!!! /*** SSC-EWI-0068 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE ***/!!!
CREATE OR REPLACE PROCEDURE PURCHASING.GetFiscalYear (DATE TIMESTAMP_NTZ(3))
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "07/11/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
 DECLARE
  FISCALYEAR INT;
  CURMONTH INT;
 BEGIN
   
   
  CURMONTH := DATE_PART(month, :DATE :: TIMESTAMP);
  FISCALYEAR := DATE_PART(year, :DATE :: TIMESTAMP);
  IF ((:CURMONTH >= 7)) THEN
   BEGIN
    FISCALYEAR := :FISCALYEAR + 1;
   END;
  END IF;
  RETURN :FISCALYEAR;
 END;
$$;

SELECT
 PURCHASING.GetFiscalYear('2020-10-10') !!!RESOLVE EWI!!! /*** SSC-EWI-0067 - UDF WAS TRANSFORMED TO SNOWFLAKE PROCEDURE, CALLING PROCEDURES INSIDE QUERIES IS NOT SUPPORTED ***/!!! as DATE;
Copy
Consulta 2
!!!RESOLVE EWI!!! /*** SSC-EWI-0068 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE ***/!!!
CREATE OR REPLACE PROCEDURE PURCHASING.getCleanChargeCode (CHARGECODE STRING)
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "07/16/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
 DECLARE
  CLEANCHARGECODE VARCHAR(50);
  LEN INT;
  POS INT := 2;
 BEGIN
   
  POS := LEN(:CHARGECODE)-1;
  WHILE (:POS > 1) LOOP
   CLEANCHARGECODE := RIGHT(:CHARGECODE, :POS);
   IF (CAST(:CLEANCHARGECODE AS BIGINT) /*** SSC-FDM-TS0005 - TRY_CONVERT/TRY_CAST COULD NOT BE CONVERTED TO TRY_CAST ***/!!!RESOLVE EWI!!! /*** SSC-EWI-TS0074 - CAST RESULT MAY BE DIFFERENT FROM TRY_CAST FUNCTION DUE TO MISSING DEPENDENCIES ***/!!! is not null) THEN
    RETURN :CLEANCHARGECODE;
   END IF;
   POS := :POS -1;
  END LOOP;
  POS := LEN(:CHARGECODE)-1;
  WHILE (:POS > 1) LOOP
   CLEANCHARGECODE := LEFT(:CHARGECODE, :POS);
   IF (CAST(:CLEANCHARGECODE AS BIGINT) /*** SSC-FDM-TS0005 - TRY_CONVERT/TRY_CAST COULD NOT BE CONVERTED TO TRY_CAST ***/!!!RESOLVE EWI!!! /*** SSC-EWI-TS0074 - CAST RESULT MAY BE DIFFERENT FROM TRY_CAST FUNCTION DUE TO MISSING DEPENDENCIES ***/!!! is not null) THEN
    RETURN :CLEANCHARGECODE;
   END IF;
   POS := :POS -1;
  END LOOP;
  RETURN null;
 END;
$$;

SELECT
 PURCHASING.getCleanChargeCode('16test') !!!RESOLVE EWI!!! /*** SSC-EWI-0067 - UDF WAS TRANSFORMED TO SNOWFLAKE PROCEDURE, CALLING PROCEDURES INSIDE QUERIES IS NOT SUPPORTED ***/!!! AS CleanChargeCode;
Copy
Resultado 1

DATE

2021.0

Resultado 2

CLEANCHARGECODE

16

Problemas conhecidos

Aviso

As funções definidas pelo usuário não podem ser usadas para executar ações que modifiquem o estado do banco de dados

Aviso

As funções definidas pelo usuário não podem conter uma cláusula OUTPUT INTO que tenha uma tabela como destino

Aviso

As funções definidas pelo usuário não podem DECLARE, OPEN, FETCH, CLOSE ou DEALLOCATE um CURSOR. Use um procedimento armazenado se você precisar usar cursores.

Aviso

As funções definidas pelo usuário não podem executar instruções de controle de fluxo, como WHILE, se houver pelo menos uma chamada ao banco de dados

Aviso

As funções definidas pelo usuário com referências a outras funções definidas pelo usuário que foram transformadas em procedimentos armazenados também serão transformadas em procedimentos armazenados.

Aviso

As funções definidas pelo usuário que usam @@ROWCOUNT não são suportadas no SQL e devem ser transformadas em procedimentos armazenados para manter a equivalência funcional.

Aviso

As funções definidas pelo usuário que têm instruções SELECT atribuindo uma variável a si mesmas não são compatíveis com o Snowflake. Consulte também SELECT @local_variable

Para todos os casos sem suporte, consulte o EWIs relacionado e os padrões abaixo para obter recomendações e possíveis soluções alternativas.

Condicionais que não sejam instruções if/else ao lado de consultas

O próximo cenário envolve o uso da instrução «while» junto com outras consultas. O problema com esse exemplo é que não há como transformar a instrução while em CTE dentro da cláusula WITH de Select principal, o que nos força a transformar essa instrução em um procedimento JavaScript para manter a mesma lógica.

SQL Server
Consulta
CREATE OR ALTER FUNCTION PURCHASING.FOO()
RETURNS INT
AS
BEGIN
    DECLARE @i int = 0, @p int;
    Select @p = COUNT(*) FROM PURCHASING.VENDOR
    
    WHILE (@p < 1000)
    BEGIN
        SET @i = @i + 1
        SET @p = @p + @i
    END
        
    IF (@i = 6)
        RETURN 1
    
    RETURN @p
END

GO

SELECT PURCHASING.FOO() as result;
Copy
Resultado

resultado

1007

Snowflake

Consulta
 !!!RESOLVE EWI!!! /*** SSC-EWI-0068 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE ***/!!!
CREATE OR REPLACE PROCEDURE PURCHASING.FOO ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "07/11/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
    DECLARE
        I INT := 0;
        P INT;
    BEGIN
         
        Select
            COUNT(*)
        INTO
            :P
 FROM
            PURCHASING.VENDOR;
        WHILE (:P < 1000) LOOP
            I := :I + 1;
            P := :P + :I;
        END LOOP;
        IF ((:I = 6)) THEN
            RETURN 1;
        END IF;
        RETURN :P;
    END;
$$;

SELECT
    PURCHASING.FOO() !!!RESOLVE EWI!!! /*** SSC-EWI-0067 - UDF WAS TRANSFORMED TO SNOWFLAKE PROCEDURE, CALLING PROCEDURES INSIDE QUERIES IS NOT SUPPORTED ***/!!! as result;
Copy
Resultado

FOO

1007

Atribuir uma variável usando seu próprio valor ao iterar por um conjunto de linhas

No exemplo a seguir, a variável @names é usada para concatenar vários valores de uma coluna em uma única cadeia de caracteres. A variável é atualizada em cada iteração, conforme mostrado, o que não é suportado pelos SnowFlake UDFs. Para esse cenário, a função deve ser transformada em um procedimento.

SQL Server

Consulta
CREATE OR ALTER FUNCTION PURCHASING.FOO()
RETURNS VARCHAR(8000)
AS
BEGIN
    DECLARE @names varchar(8000)
    SET @names = ''
    SELECT @names = ISNULL(@names + ' ', '') + Name from Purchasing.Vendor v 
    return @names              
END

GO

select PURCHASING.FOO() as names;
Copy
Resultado

nomes

Australia Bike Retailer Allenson Cycles Advanced Bicycles Trikes, Inc. Morgan Bike Accessories Cycling Master Chicago Rent-All Greenwood Athletic Company Compete Enterprises, Inc International Light Speed Training Systems Gardner Touring Cycles Internati

Consulta do Snowflake

!!!RESOLVE EWI!!! /*** SSC-EWI-0068 - USER DEFINED FUNCTION WAS TRANSFORMED TO SNOWFLAKE PROCEDURE ***/!!!
CREATE OR REPLACE PROCEDURE PURCHASING.FOO ()
RETURNS VARCHAR
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "07/11/2025",  "domain": "no-domain-provided" }}'
EXECUTE AS CALLER
AS
$$
    DECLARE
        NAMES VARCHAR(8000);
    BEGIN
         
        NAMES := '';
        SELECT
            NVL(:NAMES || ' ', '') + Name
        INTO
            :NAMES
        from
            Purchasing.Vendor v;
        RETURN :NAMES;
    END;
$$;

select
    PURCHASING.FOO() !!!RESOLVE EWI!!! /*** SSC-EWI-0067 - UDF WAS TRANSFORMED TO SNOWFLAKE PROCEDURE, CALLING PROCEDURES INSIDE QUERIES IS NOT SUPPORTED ***/!!! as names;
Copy

Aviso

Para os cenários descritos acima, considere as seguintes limitações:

  1. Todas as chamadas para funções definidas pelo usuário nas consultas DML, como SELECT, INSERT, DELETE, UPDATE ou MERGE, falharão porque não são permitidas chamadas para procedimentos armazenados nessas consultas.

  2. As chamadas para funções definidas pelo usuário dentro de procedimentos devem ser precedidas pela palavra-chave CALL.

  3. As funções definidas pelo usuário usadas em COMPUTED COLUMNS falharão durante a execução.

EWIs relacionados

  1. SSC-EWI-0067: UDF foi transformado em um procedimento Snowflake, não há suporte para a chamada de procedimentos dentro de uma consulta.

  2. SSC-EWI-0068: a função definida pelo usuário foi transformada em um procedimento Snowflake.

  3. SSC-EWI-0073: Revisão de equivalência funcional pendente.

UDF do Script Snowflake (SCALAR)

Referência de tradução de funções definidas pelo usuário escalares do SQL Server para UDFs do Script Snowflake

Applies to
  • SQL Server

  • Azure Synapse Analytics

Descrição

O SnowConvert é compatível com a tradução de funções definidas pelo usuário escalares do SQL Server diretamente para UDFs do Script Snowflake (UDFs do SnowScript) quando atenderem a critérios específicos, em vez de converter todas as funções em procedimentos armazenados.

UDFs do Script Snowflake são funções definidas pelo usuário escritas usando a sintaxe da linguagem de procedimento do Snowflake (Snowscript) dentro do corpo de uma UDF SQL. Elas aceitam variáveis, loops, lógica condicional e tratamento de exceções.

Quando as funções se tornam UDFs do SnowScript

O SnowConvert analisa cada função do SQL Server e determina automaticamente o destino apropriado do Snowflake. Uma função se torna uma UDF do SnowScript quando contém apenas lógica de procedimento sem operações de acesso a dados.

Amostra de padrões da origem

Função de cálculo simples

Uma função escalar básica que realiza cálculos sem consultar dados.

SQL Server
CREATE FUNCTION dbo.CalculateProfit
(
    @Cost DECIMAL(10,2),
    @Revenue DECIMAL(10,2)
)
RETURNS DECIMAL(10,2)
AS
BEGIN
    DECLARE @Profit DECIMAL(10,2)
    SET @Profit = @Revenue - @Cost
    RETURN @Profit
END
GO

SELECT dbo.CalculateProfit(100.00, 150.00) as Profit;
Copy
Resultado

Lucro

50,00

Snowflake (UDF do SnowScript)
CREATE OR REPLACE FUNCTION dbo.CalculateProfit (COST DECIMAL(10,2), REVENUE DECIMAL(10,2))
RETURNS DECIMAL(10, 2)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "10/09/2025",  "domain": "no-domain-provided",  "migrationid": "QsqZARsvG3aeleeXZB43fg==" }}'
AS
$$
   DECLARE
 PROFIT DECIMAL(10, 2);
   BEGIN
  
 PROFIT := :REVENUE - :COST;
 RETURN :PROFIT;
   END;
$$;

SELECT
   dbo.CalculateProfit(100.00, 150.00) as Profit;
Copy
Resultado

PROFIT

50,00

Função com lógica condicional (IF/ELSE)

Funções usadas por instruções IF/ELSE para lógica de negócios.

SQL Server
CREATE FUNCTION dbo.GetDiscountRate
(
    @CustomerType VARCHAR(20),
    @OrderAmount DECIMAL(10,2)
)
RETURNS DECIMAL(5,2)
AS
BEGIN
    DECLARE @Discount DECIMAL(5,2)
    
    IF @CustomerType = 'Premium'
        SET @Discount = 0.15
    ELSE IF @CustomerType = 'Standard'
        SET @Discount = 0.10
    ELSE
        SET @Discount = 0.05
    
    IF @OrderAmount > 1000
        SET @Discount = @Discount + 0.05
    
    RETURN @Discount
END
GO

SELECT dbo.GetDiscountRate('Premium', 1200.00) as DiscountRate;
Copy
Resultado

DiscountRate

0.20

Snowflake (UDF do SnowScript)
CREATE OR REPLACE FUNCTION dbo.GetDiscountRate (CUSTOMERTYPE STRING, ORDERAMOUNT DECIMAL(10,2))
RETURNS DECIMAL(5, 2)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "10/09/2025",  "domain": "no-domain-provided",  "migrationid": "QsqZARsvG3aeleeXZB43fg==" }}'
AS
$$
   DECLARE
 DISCOUNT DECIMAL(5, 2);
   BEGIN
  
 IF (:CUSTOMERTYPE = 'Premium') THEN
 DISCOUNT := 0.15;
 ELSEIF (:CUSTOMERTYPE = 'Standard') THEN
 DISCOUNT := 0.10;
 ELSE
 DISCOUNT := 0.05;
 END IF;
 IF (:ORDERAMOUNT > 1000) THEN
 DISCOUNT := :DISCOUNT + 0.05;
 END IF;
 RETURN :DISCOUNT;
   END;
$$;

SELECT
   dbo.GetDiscountRate('Premium', 1200.00) as DiscountRate;
Copy
Resultado

DISCOUNTRATE

0.20

Função com loop WHILE

Funções usadas por loops WHILE para cálculos iterativos.

SQL Server
CREATE FUNCTION dbo.Factorial
(
    @Number INT
)
RETURNS BIGINT
AS
BEGIN
    DECLARE @Result BIGINT = 1
    DECLARE @Counter INT = 1
    
    WHILE @Counter <= @Number
    BEGIN
        SET @Result = @Result * @Counter
        SET @Counter = @Counter + 1
    END
    
    RETURN @Result
END
GO

SELECT dbo.Factorial(5) as FactorialResult;
Copy
Resultado

FactorialResult

120

Snowflake (UDF do SnowScript)
CREATE OR REPLACE FUNCTION dbo.Factorial (NUMBER INT)
RETURNS BIGINT
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "10/09/2025",  "domain": "no-domain-provided",  "migrationid": "QsqZARsvG3aeleeXZB43fg==" }}'
AS
$$
  DECLARE
  RESULT BIGINT := 1;
  COUNTER INT := 1;
  BEGIN
  
    WHILE (:COUNTER <= :NUMBER) LOOP
      RESULT := :RESULT * :COUNTER;
      COUNTER := :COUNTER + 1;
    END LOOP;
    RETURN :RESULT;
  END;
$$;

SELECT
   dbo.Factorial(5) as FactorialResult;
Copy
Resultado

FACTORIALRESULT

120

Função de manipulação de cadeia de caracteres

Operações complexas de cadeia de caracteres usando loops e lógica condicional.

SQL Server
CREATE FUNCTION dbo.CleanPhoneNumber
(
    @Phone VARCHAR(20)
)
RETURNS VARCHAR(10)
AS
BEGIN
    DECLARE @Clean VARCHAR(10) = ''
    DECLARE @i INT = 1
    DECLARE @Char CHAR(1)
    
    WHILE @i <= LEN(@Phone)
    BEGIN
        SET @Char = SUBSTRING(@Phone, @i, 1)
        IF @Char BETWEEN '0' AND '9'
            SET @Clean = @Clean + @Char
        SET @i = @i + 1
    END
    
    RETURN @Clean
END
GO

SELECT dbo.CleanPhoneNumber('(555) 123-4567') as CleanPhone;
Copy
Resultado

CleanPhone

5551234567

Snowflake (UDF do SnowScript)
CREATE OR REPLACE FUNCTION dbo.CleanPhoneNumber (PHONE STRING)
RETURNS VARCHAR(10)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "10/09/2025",  "domain": "no-domain-provided",  "migrationid": "QsqZARsvG3aeleeXZB43fg==" }}'
AS
$$
   DECLARE
 CLEAN VARCHAR(10) := '';
 I INT := 1;
 CHAR CHAR(1);
   BEGIN
  
  
  
 WHILE (:I <= LEN(:PHONE)) LOOP
 CHAR := SUBSTRING(:PHONE, :I, 1);
 IF (:CHAR BETWEEN '0' AND '9') THEN
  CLEAN := :CLEAN + :CHAR;
 END IF;
 I := :I + 1;
 END LOOP;
 RETURN :CLEAN;
   END;
$$;

SELECT
   dbo.CleanPhoneNumber('(555) 123-4567') as CleanPhone;
Copy
Resultado

CLEANPHONE

5551234567

Lógica da instrução CASE

Funções usando expressões CASE para categorização.

SQL Server
CREATE FUNCTION dbo.GetGrade
(
    @Score INT
)
RETURNS CHAR(1)
AS
BEGIN
    DECLARE @Grade CHAR(1)
    
    SET @Grade = CASE
        WHEN @Score >= 90 THEN 'A'
        WHEN @Score >= 80 THEN 'B'
        WHEN @Score >= 70 THEN 'C'
        WHEN @Score >= 60 THEN 'D'
        ELSE 'F'
    END
    
    RETURN @Grade
END
GO

SELECT dbo.GetGrade(85) as Grade;
Copy
Resultado

Nota

B

Snowflake (UDF do SnowScript)
CREATE OR REPLACE FUNCTION dbo.GetGrade (SCORE INT)
RETURNS CHAR(1)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "10/09/2025",  "domain": "no-domain-provided",  "migrationid": "QsqZARsvG3aeleeXZB43fg==" }}'
AS
$$
   DECLARE
 GRADE CHAR(1);
   BEGIN
  
 CASE
 WHEN :SCORE >= 90 THEN
  GRADE := 'A';
 WHEN :SCORE >= 80 THEN
  GRADE := 'B';
 WHEN :SCORE >= 70 THEN
  GRADE := 'C';
 WHEN :SCORE >= 60 THEN
  GRADE := 'D';
 ELSE
  GRADE := 'F';
 END;
 RETURN :GRADE;
   END;
$$;

SELECT
   dbo.GetGrade(85) as Grade;
Copy
Resultado

GRADE

B

Select Into variable assingment

Functions using simple select into for variable assignment.

SQL Server
CREATE FUNCTION dbo.CalculatePrice
(
    @BasePrice DECIMAL(10, 2),
    @Quantity INT
)
RETURNS DECIMAL(10, 2)
AS
BEGIN
    DECLARE @Discount DECIMAL(5, 2);
    DECLARE @Subtotal DECIMAL(10, 2);
    DECLARE @FinalPrice DECIMAL(10, 2);
    
    SELECT @Discount = CASE 
                           WHEN @Quantity >= 10 THEN 0.15
                           WHEN @Quantity >= 5 THEN 0.10
                           ELSE 0.05
                       END,
           @Subtotal = @BasePrice * @Quantity;
    
    SET @FinalPrice = @Subtotal * (1 - @Discount);
    
    RETURN @FinalPrice;
END;
Copy
Resultado

CALCULATEPRICE(100, 3)

285

Snowflake (UDF do SnowScript)
CREATE OR REPLACE FUNCTION dbo.CalculatePrice (BASEPRICE DECIMAL(10, 2), QUANTITY INT)
RETURNS DECIMAL(10, 2)
LANGUAGE SQL
COMMENT = '{ "origin": "sf_sc", "name": "snowconvert", "version": {  "major": 0,  "minor": 0,  "patch": "0" }, "attributes": {  "component": "transact",  "convertedOn": "11/26/2025",  "domain": "no-domain-provided",  "migrationid": "T8GaASfFsHeOffK4v3SnIQ==" }}'
AS
$$
    DECLARE
        DISCOUNT DECIMAL(5, 2);
        SUBTOTAL DECIMAL(10, 2);
        FINALPRICE DECIMAL(10, 2);
    BEGIN
         
         
         
        DISCOUNT := CASE
                                      WHEN :QUANTITY >= 10 THEN 0.15
                                      WHEN :QUANTITY >= 5 THEN 0.10
                                      ELSE 0.05
                                  END;
        SUBTOTAL := :BASEPRICE * :QUANTITY;
        FINALPRICE := :SUBTOTAL * (1 - :DISCOUNT);
        RETURN :FINALPRICE;
    END;
$$;
Copy
Resultado

CALCULATEPRICE(100, 3)

285

Problemas conhecidos

Aviso

SnowConvert AI will not translate UDFs containing the following elements into SnowScripting UDFs, as these features are unsupported in SnowScripting UDFs:

  • acessar tabelas de banco de dados

  • usar cursores

  • chamar outras UDFs

  • conter funções agregadas ou de janela

  • realizar operações DML (INSERT/UPDATE/DELETE)

  • retornar conjuntos de resultados

EWIs relacionados

  1. SSC-EWI-0067: UDF foi transformado em um procedimento Snowflake, não há suporte para a chamada de procedimentos dentro de uma consulta.

  2. SSC-EWI-0068: a função definida pelo usuário foi transformada em um procedimento Snowflake.

  3. SSC-EWI-0073: Revisão de equivalência funcional pendente.