SnowConvert AI - Serveur SQL - CREATE FUNCTION

Référence de traduction pour les fonctions définies par l’utilisateur Transact-SQL

Applies to
  • SQL Server

  • Azure Synapse Analytics

Description

SQL Server ne prend en charge que deux types de fonctions définies par l’utilisateur :

À partir de ces types d’UDFs, il est possible de les sous-catégoriser en simples et complexes, selon la logique interne.

UDFs simples, fait correspondre la syntaxe du serveur SQL à la syntaxe de Snowflake. Ce type n’ajoute aucune logique et va directement au résultat. Ils correspondent généralement aux SQL UDFs de Snowflake. SnowConvert prend en charge la traduction des fonctions d’utilisateur scalaires du serveur SQL directement vers les UDFs Exécution de scripts Snowflake lorsqu’ils répondent à des critères spécifiques.\ \ UDFs complexes, fait un usage courant d’une instruction particulière (INSERT, DELETE, UPDATE, SET, DECLARE, etc) or control-of-flow blocks (IF…ELSE, WHILE, etc) et représente généralement une erreur de correspondance ou une violation de la définition des SQL UDFs de Snowflake.

Limitations

Les UDFs Transact présentent certaines limites qui ne sont pas présentes dans d’autres moteurs de base de données (comme Oracle et Teradata). Ces limites facilitent les traductions en réduisant le champ d’application de l’échec. Cela signifie qu’il existe des scénarios spécifiques que nous pouvons espérer éviter.

Voici quelques-unes des limites de SQL Server applicables aux UDFs

  • Les UDFs ne peuvent pas être utilisées pour effectuer des actions qui modifient l’état de la base de données

  • Les fonctions définies par l’utilisateur ne peuvent pas contenir de clause OUTPUT INTO ayant une table pour cible

  • Les fonctions définies par l’utilisateur ne peuvent pas renvoyer plusieurs jeux de résultats. Utilisez une procédure stockée si vous devez renvoyer plusieurs jeux de résultats.

Pour obtenir la liste complète, consultez le lien Créer des fonctions définies par l’utilisateur (moteur de base de données)

scalaire.md

inline-table-valued.md

INLINE TABLE-VALUED

Référence de traduction pour convertir une UDF Transact-SQL (Fonctions définies par l’utilisateur) avec type de retour TABLE vers Snowflake.

Applies to
  • SQL Server

  • Azure Synapse Analytics

Description

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Les fonctions en ligne à valeur de table sont des expressions de table qui peuvent accepter des paramètres, exécuter une instruction SELECT et renvoyer une TABLE (Référence linguistique SQL Server Création d’une fonction à valeur de table intégrée.)

Syntaxe 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

Syntaxe 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

Modèles d’échantillons de sources

La section suivante décrit tous les modèles de code source pouvant apparaître dans ce type de syntaxe CREATE FUNCTION.

Pour les fonctions en ligne à valeur de table, il ne peut y avoir qu’une seule instruction par corps qui puisse être :

  • Instruction SELECT

  • Expression de table commune WITH

Sélectionner et retourner des valeurs directement à partir d’une table

Il s’agit du scénario le plus simple, qui consiste à effectuer une simple sélection dans une table et à renvoyer les valeurs correspondantes

Transact-SQL
Valeur de table en ligne
CREATE FUNCTION GetDepartmentInfo()
RETURNS TABLE
AS
RETURN
(
  SELECT DepartmentID, Name, GroupName
  FROM HumanResources.Department
);

GO

SELECT * from GetDepartmentInfo()
Copy
Résultat

DepartmentID

Nom

GroupName

1

Engineering

Recherche et développement

2

Conception d’outils

Recherche et développement

3

Sales

Ventes et marketing

4

Marketing

Ventes et marketing

5

Achats

Gestion des stocks

6

Recherche et développement

Recherche et développement

7

Production

Fabrication

8

Contrôle de la production

Fabrication

9

Ressources humaines

Exécution générale et administration

10

Finances

Exécution générale et administration

11

Services d’information

Exécution générale et administration

12

Contrôle des documents

Assurance qualité

13

Assurance qualité

Assurance qualité

14

Installations et entretien

Exécution générale et administration

15

Expédition et réception

Gestion des stocks

16

Exécution

Exécution générale et administration

Snowflake SQL
Valeur de table en ligne
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
Résultat

DepartmentID

Nom

GroupName

1

Engineering

Recherche et développement

2

Conception d’outils

Recherche et développement

3

Sales

Ventes et marketing

4

Marketing

Ventes et marketing

5

Achats

Gestion des stocks

6

Recherche et développement

Recherche et développement

7

Production

Fabrication

8

Contrôle de la production

Fabrication

9

Ressources humaines

Exécution générale et administration

10

Finances

Exécution générale et administration

11

Services d’information

Exécution générale et administration

12

Contrôle des documents

Assurance qualité

13

Assurance qualité

Assurance qualité

14

Installations et entretien

Exécution générale et administration

15

Expédition et réception

Gestion des stocks

16

Exécution

Exécution générale et administration

Sélectionner et retourner des valeurs à partir de plusieurs tables en renommant les colonnes et en utilisant des fonctions intégrées

Voici un exemple de requête utilisant des fonctions intégrées dans une instruction Select pour obtenir des données de différentes tables, renommer les colonnes et renvoyer une table.

Transact-SQL
Valeur de table en ligne
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
Résultat

PersonType

FirstName

JobTitle

Sexe

HIREYEAR

EM

Ken

Directeur général

M

2009

EM

Terri

Vice-président de l’ingénierie

F

2008

EM

Roberto

Directeur de l’ingénierie

M

2007

EM

Rob

Concepteur d’outils en chef

M

2007

EM

Gail

Ingénieur conception

F

2008

EM

Jossef

Ingénieur conception

M

2008

EM

Dylan

Directeur de la recherche et du développement

M

2009

EM

Diane

Ingénieur Recherche et Développement

F

2008

EM

Gigi

Ingénieur Recherche et Développement

F

2009

EM

Michael

Directeur de la recherche et du développement

M

2009

EM

Ovidiu

Concepteur d’outils en chef

M

2010

EM

Thierry

Créateur d’outils

M

2007

EM

Janice

Créateur d’outils

F

2010

EM

Michael

Ingénieur conception

M

2010

EM

Sharon

Ingénieur conception

F

2011

EM

David

Directeur du marketing

M

2007

EM

Kevin

Assistant marketing

M

2007

EM

John

Spécialiste marketing

M

2011

EM

Mary

Assistant marketing

F

2011

EM

Wanida

Assistant marketing

F

2011

Snowflake SQL
Valeur de table en ligne
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
Résultat

PersonType

FirstName

JobTitle

Sexe

HIREYEAR

EM

Ken

Directeur général

M

2009

EM

Terri

Vice-président de l’ingénierie

F

2008

EM

Roberto

Directeur de l’ingénierie

M

2007

EM

Rob

Concepteur d’outils en chef

M

2007

EM

Gail

Ingénieur conception

F

2008

EM

Jossef

Ingénieur conception

M

2008

EM

Dylan

Directeur de la recherche et du développement

M

2009

EM

Diane

Ingénieur Recherche et Développement

F

2008

EM

Gigi

Ingénieur Recherche et Développement

F

2009

EM

Michael

Directeur de la recherche et du développement

M

2009

EM

Ovidiu

Concepteur d’outils en chef

M

2010

EM

Thierry

Créateur d’outils

M

2007

EM

Janice

Créateur d’outils

F

2010

EM

Michael

Ingénieur conception

M

2010

EM

Sharon

Ingénieur conception

F

2011

EM

David

Directeur du marketing

M

2007

EM

Kevin

Assistant marketing

M

2007

EM

John

Spécialiste marketing

M

2011

EM

Mary

Assistant marketing

F

2011

EM

Wanida

Assistant marketing

F

2011

Sélectionnez des colonnes à l’aide de l’instruction WITH

Le corps d’une fonction à valeur de table intégrée peut également être spécifié à l’aide d’une instruction WITH, comme indiqué ci-dessous.

Transact-SQL
Valeur de table en ligne
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
Résultat

MaritalStatus

Sexe

Nom

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

Loren Line

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
Valeur de table en ligne
 --** 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
Résultat

MaritalStatus

Sexe

Nom

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

Loren Line

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

Problèmes connus

Aucun problème n’a été trouvé

MULTI-STATEMENT TABLE-VALUED

Référence de traduction pour convertir une UDF Transact-SQL (Fonctions définies par l’utilisateur) avec type de retour TABLE vers Snowflake.

Applies to
  • SQL Server

  • Azure Synapse Analytics

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Note

Tous les exemples de code de cette page n’ont pas encore été implémentés dans SnowConvert AI. Ils doivent être interprétés comme une référence pour la manière dont chaque scénario doit être traduit dans Snowflake. Ces traductions peuvent changer à l’avenir. Certaines parties du code de sortie sont omises pour des raisons de clarté.

Description

La valeur de table multi-instructions est similaire à la valeur de table des instructions en ligne (INLINE TABLE-VALUED). Cependant, les valeurs de table multi-instructions peuvent avoir plusieurs instructions dans son corps de fonction, les colonnes de la table sont spécifiées dans le type de retour et il a un bloc BEGIN/END (Référence du langage du serveur SQL créant une fonction à valeur de table multi-instructions

Syntaxe 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

Modèles d’échantillons de sources

La section suivante décrit tous les modèles de code source possibles qui peuvent apparaître dans ce type de syntaxe ofCREATE FUNCTION.

Le corps de la fonction à valeur de table multi-instructions doit être une instruction SELECT. C’est pourquoi les autres instructions doivent être appelées séparément.

Insérer des valeurs dans une table

Insère une ou plusieurs lignes dans la table et renvoie la table avec les nouvelles valeurs

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
Résultat

BEHAVIORAL_SEGMENT

Inconnu

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
Résultats

BEHAVIORAL_SEGMENT

Inconnu

Insérer une valeur en fonction de l’instruction if/else

Insère une ligne dans la table conformément à la condition et renvoie la table avec la nouvelle valeur

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
Résultat

NUMBER_TYPE

Impair

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
Résultat

NUMBER_TYPE

Impair

Insère plusieurs éléments en fonction de l’instruction if/else

L’exemple ci-dessous insère plusieurs valeurs dans la table et plusieurs variables sont modifiées en fonction de la condition. Renvoie la table contenant les nouvelles valeurs

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
Résultat

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
Résultat

ID_EMPLOYEE

WORKING_FROM_HOME

TEAM

COMPUTER

123456789

1

TEAM_1

LAPTOP

Avertissement

Dans le cas d’instructions if imbriquées et si plusieurs variables sont modifiées dans les instructions, il est nécessaire d’utiliser une procédure stockée.

Mise à jour des valeurs précédemment insérées

Met à jour les valeurs des colonnes de la table dans le corps de la fonction et la renvoie avec les nouvelles valeurs.

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
Résultat

DEPARTMENT_NAME

FIRST_NAME

LAST_NAME

START_DATE

END_DATE

JOB_TITLE

MONTHS_WORKING

Sales

Syed

Abbas

2013-03-14

NULL

Directeur des ventes Pacifique

106

Production

Kim

Abercombie

2010-01-16

NULL

Technicienne de production - WC60

144

Assurance qualité

Hazem

Abolrous

2009-02-28

NULL

Manager de l’assurance qualité

155

Expédition et réception

Pilar

Ackerman

2009-01-02

NULL

Supervision des livraisons et des réceptions

156

Production

Jay

Adams

2009-03-05

NULL

Technicienne de production - WC60

154

Services d’information

François

Ajenstat

2009-01-17

NULL

Administrateur de la base de données

156

Sales

Amy

Alberts

2012-04-16

NULL

Directrice des ventes européennes

17

Production

Greg

Alderson

2008-12-02

NULL

Technicienne de production - WC45

157

Assurance qualité

Sean

Alexander

2008-12-28

NULL

Technicien d’assurance qualité

157

Installations et entretien

Gary

Altman

2009-12-02

NULL

Gestionnaire des ressources

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
Résultat

DEPARTMENT_NAME

FIRST_NAME

LAST_NAME

START_DATE

END_DATE

JOB_TITLE

MONTHS_WORKING

Sales

Syed

Abbas

2013-03-14

NULL

Directeur des ventes Pacifique

106

Production

Kim

Abercombie

2010-01-16

NULL

Technicienne de production - WC60

144

Assurance qualité

Hazem

Abolrous

2009-02-28

NULL

Manager de l’assurance qualité

155

Expédition et réception

Pilar

Ackerman

2009-01-02

NULL

Supervision des livraisons et des réceptions

156

Production

Jay

Adams

2009-03-05

NULL

Technicienne de production - WC60

154

Services d’information

François

Ajenstat

2009-01-17

NULL

Administrateur de la base de données

156

Sales

Amy

Alberts

2012-04-16

NULL

Directrice des ventes européennes

17

Production

Greg

Alderson

2008-12-02

NULL

Technicienne de production - WC45

157

Assurance qualité

Sean

Alexander

2008-12-28

NULL

Technicien d’assurance qualité

157

Installations et entretien

Gary

Altman

2009-12-02

NULL

Gestionnaire des ressources

145

Clauses de retour multiples

Dans l’échantillon suivant, il y a plus d’une clause de retour, car selon la situation, il n’est pas nécessaire de continuer à exécuter toute la fonction.

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
Résultat

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
Résultat

TYPE

NAME

SMALL_TEAM

TEAM1

Avertissement

Cette transformation est appliquée lorsqu’il n’y a qu’une seule valeur à insérer. S’il y a plus d’une valeur, il est nécessaire d’utiliser une procédure stockée.

Cas complexes

L’exemple est un casse complexe qui utilise des instructions imbriquées if et insère une valeur en fonction de la condition true.

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
Résultat

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
Deuxième onglet

VACATION_STATUS

OK

Problèmes connus

Instructions While avec requêtes en parallèle

Le problème de cet exemple est qu’il n’y a aucun moyen de transformer l’instruction while en CTE à l’intérieur de la clause WITH du select principal, ce qui nous oblige à transformer cette instruction en procédure stockée pour conserver la même logique.

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
Résultat

GROUP_NAME

Conception d’outils

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
Résultat

GROUP_NAME

Conception d’outils

Déclarer le curseur

Les fonctions définies par l’utilisateur ne peuvent pas DECLARE, OPEN, FETCH, CLOSE ou DEALLOCATE a CURSOR. Utilisez une procédure stockée pour travailler avec des curseurs.

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
Résultat

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
Résultat

AMOUNT

3

Les instructions différentes ne sont pas prises en charge dans les expressions de tables communes

Les clauses UPDATE, INSERT, DELETE, ALTER ou DROP ne sont pas prises en charge dans le corps des expressions de tables communes, même après leur déclaration à l’aide d’un délimiteur. C’est pourquoi la fonction peut être modifiée pour fonctionner comme une procédure stockée.

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
Résultat

PRODUCT_NAME

Évaluation

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
Résultat

PRODUCT_NAME

Évaluation

HL Mountain Pedal

3

Mountain Bike Socks, M

5

Road-550-W Yellow, 40

5

EWIs connexes

  1. SSC-EWI-0040 : Instruction non prise en charge.

  2. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle

SCALAR

Référence de traduction pour convertir une UDF Transact-SQL (Fonctions définies par l’utilisateur) avec type de retour scalaire en Snowflake.

Applies to
  • SQL Server

  • Azure Synapse Analytics

Description

Note

Certaines parties du code de sortie sont omises pour des raisons de clarté.

Une fonction scalaire définie par l’utilisateur est une routine Transact-SQL ou de runtime de langage commun (CLR) qui accepte des paramètres, exécute une action, telle qu’un calcul complexe, et renvoie le résultat de cette action sous forme de valeur scalaire. (Sous-section ReferenceCREATE FUNCTION de langage de serveur SQL).

Note

Ces fonctions sont généralement utilisées dans l’instruction SELECT ou dans la configuration d’une seule variable (très probablement dans une procédure stockée).

Syntaxe 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

Syntaxe Snowflake

Snowflake permet l’utilisation de 3 langues différentes dans les fonctions définies par l’utilisateur :

  • SQL

  • JavaScript

  • Java

Pour l’instant, SnowConvert AI prendra en charge uniquement SQL et JavaScript comme langages cibles.

SQL

Note

Les fonctions définies par l’utilisateur SQL n’acceptent qu’une seule requête comme corps. Elles peuvent lire la base de données, mais ne sont pas autorisées à l’écrire ou à la modifier. (Référence des UDFs SQL scalaires).

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

Note

Les fonctions définies par l’utilisateur JavaScript autorisent plusieurs instructions dans leur corps, mais ne peuvent pas effectuer de requêtes dans la base de données. (Référence des UDFs JavaScript scalaires)

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

Modèles d’échantillons de sources

Instructions Set et Declare

Les instructions les plus courantes dans les corps de fonctions sont les instructions DECLARE et SET. Pour les instructions DECLARE sans valeur par défaut, la transformation sera ignorée. Les instructions SET et DECLARE avec une valeur par défaut seront transformées en COMMON TABLE EXPRESSION. Chaque expression de table commune contiendra une colonne qui représente la valeur de la variable locale.

Transact-SQL
Requête
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
Résultat

vendor_name

Australia Bike Retailer

Snowflake
Requête
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
Résultat

VENDOR_NAME

Australia Bike Retailer

Transformation des instructions If/Else

Les instructions If/Else peuvent être traitées de différentes manières, elles peuvent être transformées en Javascript ou en SQL à l’aide de CASE EXPRESSION dans Select qui permet des conditionnels à l’intérieur des requêtes, alors que la transformation en Javascript est assez simple, l’instruction Case peut ne pas être si évidente à première vue.

Transact-SQL
Requête
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
Résultat

has_active_flag

NO

Snowflake
Requête
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
Résultat

HAS_ACTIVE_FLAG

NO

Instructions imbriquées

Pour les instructions imbriquées, la programmation structurée est transformée en une requête unique. Les instructions du contrôle du flux seront imbriquées dans des structures de table afin de préserver l’ordre d’exécution.

Note

CASE EXPRESSIONS ne peut renvoyer qu’une seule valeur par instruction

Exemple

Note

Le code suivant est fonctionnellement équivalent dans les deux paradigmes de programmation.

Programmation structurée
 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
Résultat

AccountNumber

LITWARE0001

Variables conditionnelles via SELECTs

La définition et l’affectation de variables dans les instructions conditionnelles posent généralement des problèmes, car les références à la variable plus loin dans le code doivent savoir où la variable a été modifiée pour la dernière fois. De plus, si la référence se trouve à l’intérieur d’une autre instruction conditionnelle, il faudrait une sorte de redirection qui fasse référence à l’affectation précédente connue de la variable.

Le tout est aggravé par l’imbrication et les requêtes complexes qui peuvent être trouvées sur le code d’entrée. C’est pourquoi un EWI est ajouté lorsque ces modèles sont trouvés.

Dans le scénario suivant, la première instruction IF peut être transformée sans problème, car son contenu est assez simple. Les deuxième et troisième instructions IF sont commentées parce qu’elles ne sont pas prises en charge pour le moment, étant donné qu’il existe des instructions autres que les affectations de variables par le biais de SELECT.

SQL Server
Requête
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
Résultat

RESULT

10

Snowflake
Requête
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
Résultat

RESULT

10

Assigner et retourner une variable

Dans ce modèle simple, il y a une déclaration de variable, puis cette variable est définie à l’aide d’une instruction SELECT et enfin renvoyée. Celle-ci va être migrée vers une expression de table commune afin de conserver le comportement d’origine.

SQL Server
Requête
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
Résultat

Résultat

1583978.2263

Snowflake
Requête
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
Résultat

RESULT

1583978.2263

Appels de fonctions multiples

Pour ce modèle spécifique, il n’y a pas de requêtes évidentes, mais il y a plusieurs appels à plusieurs fonctions travaillant sur la même variable et la renvoyant à la fin. Comme Snowflake ne prend en charge que les requêtes à l’intérieur de ses fonctions, la solution pour ce bloc va être de l’ajouter à un Select et d’imbriquer les appels à l’intérieur, en s’assurant que la valeur de retour est la même que celle de la source.

SQL Server
Requête
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
Résultat

Nom

USA Car Retailer

Snowflake
Requête
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
Résultat

NAME

USA Car Retailer

Augmenter une variable en fonction de plusieurs conditions IF et renvoyer sa valeur

Pour ce modèle, une variable est modifiée (augmentée dans le cas présent) à l’aide de plusieurs conditions IF. Au début, un jeu de résultats est initialisé et utilisé pour déterminer si la variable de résultat doit être augmentée ou non. Enfin, la variable de résultat est renvoyée.

SQL Server
Requête
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
Résultat

Résultat

473.1415

Snowflake
Requête
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
Résultat

RESULT

473.1415

Deux ou plusieurs instructions RETURN

Pour ce modèle, le bloc IF contenant la clause de retour qui interrompt le flux de code est ajouté à la fin du corps, comme la dernière instruction à exécuter dans une expression CASE.

Cas de base

Pour ce scénario particulier, il n’y a pas de logique entre l’instruction conditionnelle RETURN et l’instruction finale RETURN, de sorte que tous les corps seront mappés sur une seule CASE EXPRESSION.

SQL Server
Requête
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
Résultat

résultat

1

Snowflake
Requête
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
Résultat

RESULT

1

Expressions de table communes

Les expressions de table communes seront conservées telles quelles dans le code d’origine et seront concaténées avec celles qui seront générées. SnowConvert AI est capable d’identifier d’abord tous les noms COMMON TABLE EXPRESSION d’origine afin d’éviter de générer des noms en double.

SQL Server
Requête
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
Résultat

résultat

3689

Snowflake
Requête
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
Résultat

RESULT

3689

Transformer en UDFs JavaScript

S’il y a plusieurs instructions et que la fonction n’accède en aucune façon à la base de données, elle peut être transformée en une fonction JavaScript en conservant l’équivalence fonctionnelle

SQL Server
Requête 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
Requête 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
Résultat 1

DATE

2021

Result 2

CleanChargeCode

16

Snowflake
Requête 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
Requête 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
Résultat 1

DATE

2021.0

Result 2

CLEANCHARGECODE

16

Problèmes connus

Avertissement

Les fonctions définies par l’utilisateur ne peuvent pas être utilisées pour effectuer des actions qui modifient l’état de la base de données

Avertissement

Les fonctions définies par l’utilisateur ne peuvent pas contenir de clause OUTPUT INTO ayant une table pour cible

Avertissement

Les fonctions définies par l’utilisateur ne peuvent pas DECLARE, OPEN, FETCH, CLOSE ou DEALLOCATE a CURSOR. Utilisez une procédure stockée si vous devez utiliser des curseurs.

Avertissement

Les fonctions définies par l’utilisateur ne peuvent pas exécuter d’instructions de contrôle du flux, telles que WHILE, s’il y a au moins un appel à la base de données

Avertissement

Les fonctions définies par l’utilisateur qui contiennent des références à d’autres fonctions définies par l’utilisateur et qui ont été transformées en procédures stockées seront également transformées en procédures stockées.

Avertissement

Les fonctions définies par l’utilisateur qui utilisent @@ROWCOUNT ne sont pas prises en charge dans SQL et doivent être transformées en procédures stockées afin de conserver l’équivalence fonctionnelle.

Avertissement

Les fonctions définies par l’utilisateur qui ont des instructions SELECT assignant une variable à elle-même ne sont pas prises en charge dans Snowflake. Voir aussi SELECT @local_variable

Pour tous les cas non pris en charge, veuillez consulter les EWIs connexes et les modèles ci-dessous pour obtenir des recommandations et des solutions de contournement.

Conditionnelles autres que les instructions if/else en parallèle des requêtes

Le scénario suivant implique l’utilisation de l’instruction « while » en parallèle d’autres requêtes. Le problème de cet exemple est qu’il n’y a aucun moyen de transformer l’instruction while en CTE à l’intérieur de la clause WITH du select principal, ce qui nous oblige à transformer cette instruction en procédure JavaScript pour conserver la même logique.

SQL Server
Requête
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
Résultat

résultat

1007

Snowflake

Requête
 !!!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
Résultat

FOO

1007

Affectation d’une variable à l’aide de sa propre valeur en parcourant un jeu de lignes

Dans l’exemple suivant, la variable @names est utilisée pour concaténer plusieurs valeurs d’une colonne en une seule chaîne. La variable est mise à jour à chaque itération comme indiqué, ce qui n’est pas pris en charge par les UDFs SnowFlake. Pour ce scénario, la fonction doit être transformée en procédure.

SQL Server

Requête
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
Résultat

names

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

Requête 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

Avertissement

Pour les scénarios décrits ci-dessus, tenez compte des limites suivantes :

  1. Tous les appels aux fonctions définies par l’utilisateur dans les requêtes DML telles que SELECT, INSERT, DELETE, UPDATE ou MERGE échoueront parce que les appels aux procédures stockées dans ces requêtes ne sont pas autorisés.

  2. Les appels à des fonctions définies par l’utilisateur à l’intérieur de procédures doivent être précédés du mot-clé CALL.

  3. Les fonctions définies par l’usage utilisées dans les COMPUTED COLUMNS échoueront lors de l’exécution.

EWIs connexes

  1. SSC-EWI-0067 : UDF a été transformée en procédure Snowflake, l’appel de procédures à l’intérieur d’une requête n’est pas pris en charge.

  2. SSC-EWI-0068 : La fonction définie par l’utilisateur a été transformée en procédure Snowflake.

  3. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.

Script Snowflake UDF (SCALAR)

Référence de traduction pour les fonctions scalaires définies par l’utilisateur du serveur SQL vers les UDFs Exécution de scripts Snowflake

Applies to
  • SQL Server

  • Azure Synapse Analytics

Description

SnowConvert prend en charge la traduction des fonctions scalaires définies par l’utilisateur du serveur SQL directement vers les UDFs Exécution de scripts Snowflake (SnowScript UDFs) lorsqu’elles répondent à des critères spécifiques, au lieu de convertir toutes les fonctions en procédures stockées.

Les UDFs Exécution de scripts Snowflake sont des fonctions définies par l’utilisateur écrites à l’aide de la syntaxe du langage procédural de Snowflake (Snowscript) au sein d’un corps SQL UDF. Elles prennent en charge les variables, les boucles, la logique conditionnelle et le traitement des exceptions.

Lorsque les fonctions deviennent des SnowScript UDFs

SnowConvert analyse chaque fonction de serveur SQL et détermine automatiquement la cible Snowflake appropriée. Une fonction devient une SnowScript UDF lorsqu’elle contient uniquement une logique procédurale sans opérations d’accès aux données.

Modèles d’échantillons de sources

Fonction de calcul simple

Une fonction scalaire de base qui effectue des calculs sans interroger de données.

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
Résultat

Bénéfice

50,00

Snowflake (UDF 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
Résultat

PROFIT

50,00

Fonction avec logique conditionnelle (IF/ELSE)

Fonctions utilisant les instructions IF/ELSE pour la logique métier.

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
Résultat

DiscountRate

0.20

Snowflake (UDF 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
Résultat

DISCOUNTRATE

0.20

Fonction avec boucle WHILE

Fonctions utilisant des boucles WHILE pour les calculs itératifs.

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
Résultat

FactorialResult

120

Snowflake (UDF 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
Résultat

FACTORIALRESULT

120

Fonction de manipulation des chaînes

Opérations de chaîne complexes utilisant des boucles et une logique conditionnelle.

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
Résultat

CleanPhone

5551234567

Snowflake (UDF 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
Résultat

CLEANPHONE

5551234567

Logique de l’instruction CASE

Fonctions utilisant les expressions CASE pour la catégorisation.

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
Résultat

Note

B

Snowflake (UDF 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
Résultat

GRADE

B

Problèmes connus

Avertissement

Les UDFs SnowScript ne peuvent pas :

  • Accéder aux tables de la base de données

  • Utiliser des curseurs

  • Appeler d’autres UDFs

  • Contenir des fonctions d’agrégation ou de fenêtre

  • Exécuter des opérations DML (INSERT/UPDATE/DELETE)

  • Renvoyer les jeux de résultats

EWIs connexes

  1. SSC-EWI-0067 : UDF a été transformée en procédure Snowflake, l’appel de procédures à l’intérieur d’une requête n’est pas pris en charge.

  2. SSC-EWI-0068 : La fonction définie par l’utilisateur a été transformée en procédure Snowflake.

  3. SSC-EWI-0073 : En attente de l’examen de l’équivalence fonctionnelle.