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)
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 [ ) ]
[ ; ]
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
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
SELECTExpressã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()
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());
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();
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());
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');
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'));
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
[ ; ]
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>'
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();
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();;
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);
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);;
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');
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');;
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();
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();;
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 < 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');
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');;
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')
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');
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 < 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);
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);;
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);
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);;
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
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();
Resultado¶
PRODUCT_NAME |
Classificação |
|---|---|
HL Mountain Pedal |
3 |
Mountain Bike Socks, M |
5 |
Road-550-W Yellow, 40 |
5 |
EWIs relacionados¶
SSC-EWI-0040: Instrução incompatível.
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
[ ; ]
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>'
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>'
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;
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;
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;
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;
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
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
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
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
;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
Aviso
Para os cenários descritos acima, considere as seguintes limitações:
Todas as chamadas para funções definidas pelo usuário nas consultas DML, como
SELECT,INSERT,DELETE,UPDATEouMERGE, falharão porque não são permitidas chamadas para procedimentos armazenados nessas consultas.As chamadas para funções definidas pelo usuário dentro de procedimentos devem ser precedidas pela palavra-chave
CALL.As funções definidas pelo usuário usadas em COMPUTED COLUMNS falharão durante a execução.
EWIs relacionados¶
SSC-EWI-0067: UDF foi transformado em um procedimento Snowflake, não há suporte para a chamada de procedimentos dentro de uma consulta.
SSC-EWI-0068: a função definida pelo usuário foi transformada em um procedimento Snowflake.
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
$$;
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¶
SSC-EWI-0067: UDF foi transformado em um procedimento Snowflake, não há suporte para a chamada de procedimentos dentro de uma consulta.
SSC-EWI-0068: a função definida pelo usuário foi transformada em um procedimento Snowflake.
SSC-EWI-0073: Revisão de equivalência funcional pendente.