SnowConvert AI - SQL Server - CREATE FUNCTION

Transact-SQL ユーザー定義関数の翻訳リファレンス

Applies to
  • SQL Server

  • Azure Synapse Analytics

説明

SQL Serverは、2種類の ユーザー定義関数 のみをサポートしています。

これらの UDFs 型を使用すると、内部ロジックに従って 単純なものと複雑なもの にサブカテゴリー化することが可能です。

単純 UDFs は SQL Server構文をSnowflake構文と一致させます。この型はロジックを追加せず、結果に直接向かいます。これらは通常、Snowflakeの SQL UDFs に一致します。 SnowConvert は、特定の基準を満たしている場合、 SQL Serverスカラーユーザー定義関数の Snowflakeスクリプト UDFs への直接的な翻訳をサポートしています。\ \ 複雑な UDFs は特定のステートメント( INSERTDELETEUPDATESETDECLARE など)や control-of-flow ブロック( IF...ELSEWHILE など)を広く使用し、通常Snowflakeの SQL UDFs 定義との不一致や違反を表します。

制限事項

Transact UDFs は、他のデータベースエンジン(OracleやTeradataなど)にはない制限があります。これらの制限は、失敗の範囲を狭めることによって翻訳に役立ちます。つまり、避けるべきシナリオがあるということです。

以下に、SQL Serverが UDFs に対して持つ制限の一部を示します

  • UDFs はデータベースの状態を変更するアクションの実行には使用できません

  • ユーザー定義関数に、テーブルをターゲットとする OUTPUT INTO 句を含めることはできません

  • ユーザー定義関数は複数の結果セットを返すことはできません。複数の結果セットを返す必要がある場合は、ストアドプロシージャを使用します。

全リストはこちらのリンク ユーザー定義関数の作成(データベースエンジン)をご覧ください

scalar.md

inline-table-valued.md

INLINE TABLE-VALUED

TABLE 戻り型を持つTransact-SQL UDF (ユーザー定義関数)をSnowflakeに変換するための翻訳リファレンス。

Applies to
  • SQL Server

  • Azure Synapse Analytics

説明

注釈

わかりやすくするため、出力コードの一部を省略しています。

Inline Table-Valued関数は、パラメーターを受け取り、SELECT ステートメントを実行し、TABLE (SQL Server言語リファレンスInline Table-Valued関数の作成) を返すことができるテーブル式です。

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 [ ) ]
[ ; ]

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

サンプルソースパターン

次のセクションでは、この種の CREATE FUNCTION 構文で出現し得るすべてのソースコードパターンについて説明します。

Inline Table-Valued関数の場合、本文ごとに次のステートメントが1つだけ存在できます。

  • SELECT ステートメント

  • WITH 共通テーブル式

1つのテーブルから直接値を選択して返す

これは最も単純なシナリオで、テーブルから単純なselectを実行し、その値を返します

Transact-SQL
インラインTable-Valued
CREATE FUNCTION GetDepartmentInfo()
RETURNS TABLE
AS
RETURN
(
  SELECT DepartmentID, Name, GroupName
  FROM HumanResources.Department
);

GO

SELECT * from GetDepartmentInfo()
結果

DepartmentID

名前

GroupName

1

エンジニアリング

研究開発

2

ツールデザイン

研究開発

3

販売

セールス&マーケティング

4

マーケティング

セールス&マーケティング

5

購買

在庫管理

6

研究開発

研究開発

7

実稼働

製造

8

生産管理

製造

9

人事

経営全般および管理

10

ファイナンス

経営全般および管理

11

情報サービス

経営全般および管理

12

ドキュメント管理

品質保証

13

品質保証

品質保証

14

施設とメンテナンス

経営全般および管理

15

出荷と入荷

在庫管理

16

経営

経営全般および管理

Snowflake SQL
インラインTable-Valued
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());
結果

DepartmentID

名前

GroupName

1

エンジニアリング

研究開発

2

ツールデザイン

研究開発

3

販売

セールス&マーケティング

4

マーケティング

セールス&マーケティング

5

購買

在庫管理

6

研究開発

研究開発

7

実稼働

製造

8

生産管理

製造

9

人事

経営全般および管理

10

ファイナンス

経営全般および管理

11

情報サービス

経営全般および管理

12

ドキュメント管理

品質保証

13

品質保証

品質保証

14

施設とメンテナンス

経営全般および管理

15

出荷と入荷

在庫管理

16

経営

経営全般および管理

列名を変更し、組み込み関数を使用して複数のテーブルから値を選択して返す

これは、selectステートメントで組み込み関数を使用して、異なるテーブルからデータを取得し、列の名前を変更してテーブルを返すクエリの例です。

Transact-SQL
インラインTable-Valued
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();
結果

PersonType

FirstName

JobTitle

性別

HIREYEAR

EM

ケン

Chief Executive Officer

M

2009

EM

Terri

Vice President of Engineering

F

2008

EM

Roberto

Engineering Manager

M

2007

EM

Rob

Senior Tool Designer

M

2007

EM

Gail

Design Engineer

F

2008

EM

Jossef

Design Engineer

M

2008

EM

Dylan

Research and Development Manager

M

2009

EM

Diane

Research and Development Engineer

F

2008

EM

Gigi

Research and Development Engineer

F

2009

EM

Michael

Research and Development Manager

M

2009

EM

Ovidiu

Senior Tool Designer

M

2010

EM

Thierry

Tool Designer

M

2007

EM

Janice

Tool Designer

F

2010

EM

Michael

Senior Design Engineer

M

2010

EM

Sharon

Design Engineer

F

2011

EM

デイビッド

Marketing Manager

M

2007

EM

Kevin

Marketing Assistant

M

2007

EM

John

Marketing Specialist

M

2011

EM

Mary

Marketing Assistant

F

2011

EM

Wanida

Marketing Assistant

F

2011

Snowflake SQL
インラインTable-Valued
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());
結果

PersonType

FirstName

JobTitle

性別

HIREYEAR

EM

ケン

Chief Executive Officer

M

2009

EM

Terri

Vice President of Engineering

F

2008

EM

Roberto

Engineering Manager

M

2007

EM

Rob

Senior Tool Designer

M

2007

EM

Gail

Design Engineer

F

2008

EM

Jossef

Design Engineer

M

2008

EM

Dylan

Research and Development Manager

M

2009

EM

Diane

Research and Development Engineer

F

2008

EM

Gigi

Research and Development Engineer

F

2009

EM

Michael

Research and Development Manager

M

2009

EM

Ovidiu

Senior Tool Designer

M

2010

EM

Thierry

Tool Designer

M

2007

EM

Janice

Tool Designer

F

2010

EM

Michael

Senior Design Engineer

M

2010

EM

Sharon

Design Engineer

F

2011

EM

デイビッド

Marketing Manager

M

2007

EM

Kevin

Marketing Assistant

M

2007

EM

John

Marketing Specialist

M

2011

EM

Mary

Marketing Assistant

F

2011

EM

Wanida

Marketing Assistant

F

2011

WITH ステートメントを使用して列を選択する

inline table-valued関数の本文は、以下のように WITH ステートメントを使用して指定することもできます。

Transact-SQL
インラインTable-Valued
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');
結果

MaritalStatus

性別

名前

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
インラインTable-Valued
 --** 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'));
結果

MaritalStatus

性別

名前

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

既知の問題

問題は見つかりませんでした

MULTI-STATEMENT TABLE-VALUED

TABLE 戻り型を持つTransact-SQL UDF (ユーザー定義関数)をSnowflakeに変換するための翻訳リファレンス。

Applies to
  • SQL Server

  • Azure Synapse Analytics

注釈

わかりやすくするため、出力コードの一部を省略しています。

注釈

このページのすべてのコードサンプルは、まだ SnowConvert AI に実装されていません。各シナリオをどのようにSnowflakeに翻訳すべきかの参照情報として解釈される必要があります。これらの翻訳は今後変更される可能性があります。わかりやすくするため、出力コードの一部を省略しています。

説明

マルチステートメントtable-valuedは、インラインステートメントtable-valuedに似ています( INLINE TABLE-VALUED )。ただし、マルチステートメントtable-valuedは、関数本体に複数のステートメントを持つことがあり、テーブル列は戻り型で指定され、 BEGIN/END ブロックを持ちます( SQL Server言語リファレンス マルチステートメントtable-valued関数の作成

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

サンプルソースパターン

次のセクションでは、この種の ofCREATE FUNCTION 構文に出てくる可能性がある、すべてのソースコードパターンについて説明します。

Multi-Statement Table-Valued関数の関数本文は、SELECT ステートメントでなければなりません。このため、他のステートメントは個別に呼び出す必要があります。

テーブルに値を挿入する

テーブルに1つ以上の行を挿入し、新しい値を含むテーブルを返す

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();
結果

BEHAVIORAL_SEGMENT

不明

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();;
結果

BEHAVIORAL_SEGMENT

不明

if/elseステートメントに従って値を挿入する

条件に従ってテーブルに行を挿入し、新しい値を含むテーブルを返す

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);
結果

NUMBER_TYPE

Odd

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);;
結果

NUMBER_TYPE

Odd

if/elseステートメントに従って複数挿入する

以下の例では、複数の値をテーブルに挿入し、条件に応じて複数の変数が変更されます。新しい値を含むテーブルを返す

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');
結果

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');;
結果

ID_EMPLOYEE

WORKING_FROM_HOME

TEAM

COMPUTER

123456789

1

TEAM_1

LAPTOP

警告

ネストされたifステートメントがあり、ステートメント内で複数の変数が変更される場合は、ストアドプロシージャを使用する必要があります。

以前に挿入した値の更新

テーブルの列値を関数本文に更新し、新しい値を返します。

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();
結果

DEPARTMENT_NAME

FIRST_NAME

LAST_NAME

START_DATE

END_DATE

JOB_TITLE

MONTHS_WORKING

販売

Syed

Abbas

2013-03-14

NULL

Pacific Sales Manager

106

実稼働

Kim

Abercrombie

2010-01-16

NULL

Production Technician - WC60

144

品質保証

Hazem

Abolrous

2009-02-28

NULL

Quality Assurance Manager

155

出荷と入荷

Pilar

Ackerman

2009-01-02

NULL

Shipping and Receiving Supervisor

156

実稼働

Jay

Adams

2009-03-05

NULL

Production Technician - WC60

154

情報サービス

François

Ajenstat

2009-01-17

NULL

Database Administrator

156

販売

Amy

Alberts

2012-04-16

NULL

European Sales Manager

117

実稼働

Greg

Alderson

2008-12-02

NULL

Production Technician - WC45

157

品質保証

Sean

Alexander

2008-12-28

NULL

Quality Assurance Technician

157

施設とメンテナンス

Gary

Altman

2009-12-02

NULL

Facilities Manager

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();;
結果

DEPARTMENT_NAME

FIRST_NAME

LAST_NAME

START_DATE

END_DATE

JOB_TITLE

MONTHS_WORKING

販売

Syed

Abbas

2013-03-14

NULL

Pacific Sales Manager

106

実稼働

Kim

Abercrombie

2010-01-16

NULL

Production Technician - WC60

144

品質保証

Hazem

Abolrous

2009-02-28

NULL

Quality Assurance Manager

155

出荷と入荷

Pilar

Ackerman

2009-01-02

NULL

Shipping and Receiving Supervisor

156

実稼働

Jay

Adams

2009-03-05

NULL

Production Technician - WC60

154

情報サービス

François

Ajenstat

2009-01-17

NULL

Database Administrator

156

販売

Amy

Alberts

2012-04-16

NULL

European Sales Manager

117

実稼働

Greg

Alderson

2008-12-02

NULL

Production Technician - WC45

157

品質保証

Sean

Alexander

2008-12-28

NULL

Quality Assurance Technician

157

施設とメンテナンス

Gary

Altman

2009-12-02

NULL

Facilities Manager

145

複数の戻り句

以下のサンプルでは戻り句が複数ありますが、これは状況に応じて関数全体を実行し続ける必要がないためです。

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');
結果

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');;
結果

TYPE

NAME

SMALL_TEAM

TEAM1

警告

この変換は、挿入する値が1つだけの場合に適用されます。複数の値がある場合は、ストアドプロシージャを使用する必要があります。

複雑なケース

この例は、ネストされた if ステートメントを使用し、真の条件に応じて値を挿入する複雑なケースです。

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')
結果

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');
2つ目のタブ

VACATION_STATUS

OK

既知の問題

クエリに沿ったWhileステートメント

この例の問題点は、メインセレクトの WITH 句の中でwhileステートメントを CTE に変換する方法がないことです。このため、同じロジックを維持するために、このステートメントをストアプロシージャに変換せざるを得ません。

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);
結果

GROUP_NAME

ツールデザイン

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);;
結果

GROUP_NAME

ツールデザイン

カーソル宣言

ユーザー定義関数は、CURSOR を DECLARE、OPEN、FETCH、CLOSE、DEALLOCATE することはできません。ストアドプロシージャを使用してカーソルを操作します。

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);
結果

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);;
結果

AMOUNT

3

共通テーブル式では、異なるステートメントはサポートされていません

UPDATEINSERTDELETEALTERDROP の句は、区切り文字を使用して宣言した後でも、共通テーブル式の本文ではサポートされていません。このため、関数をストアドプロシージャとして動作するように変更することができます。

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
結果

PRODUCT_NAME

評価

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();
結果

PRODUCT_NAME

評価

HL Mountain Pedal

3

Mountain Bike Socks, M

5

Road-550-W Yellow, 40

5

関連 EWIs

  1. SSC-EWI-0040 :ステートメントがサポートされていません。

  2. SSC-EWI-0073: 機能同等性レビュー保留中

SCALAR

スカラー戻り型を持つTransact-SQL UDF (ユーザー定義関数)をSnowflakeに変換するための翻訳リファレンス。

Applies to
  • SQL Server

  • Azure Synapse Analytics

説明

注釈

わかりやすくするため、出力コードの一部を省略しています。

スカラーユーザー定義関数は、Transact-SQL または共通言語ランタイム( CLR )ルーティンで、パラメーターを受け取り、複雑な計算などのアクションを実行し、そのアクションの結果をスカラー値として返します。( SQL Server言語 ReferenceCREATE FUNCTION サブセクション )。

注釈

これらの関数は通常、SELECT ステートメントの内部で使用されるか、単一変数のセットアップ(ストアドプロシージャの内部で使用されることがほとんどです)で使用されます。

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
[ ; ]

Snowflake構文

Snowflakeでは、ユーザー定義関数で3つの異なる言語を使用できます。

  • SQL

  • JavaScript

  • Java

今のところ、 SnowConvert AI はターゲット言語として SQLJavaScript のみをサポートします。

SQL

注釈

SQL ユーザー定義関数は、本文として1つのクエリしかサポートしていません。データベースからの読み取りは可能ですが、書き込みや変更はできません。(スカラー 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

注釈

JavaScript ユーザー定義関数は、本文中に複数のステートメントを記述することができますが、データベースへのクエリを実行することはできません。(スカラー JavaScript UDFs リファレンス)

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

サンプルソースパターン

SetおよびDeclareステートメント

関数本文で最もよく使われるステートメントは DECLARESET ステートメントです。デフォルト値のない DECLARE ステートメントでは、変換は無視されます。SET ステートメントおよびデフォルト値のある DECLARE ステートメントでは、COMMON TABLE EXPRESSION に変換されます。各共通テーブル式には、ローカル変数値を表す列が含まれます。

Transact-SQL
クエリ
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;
結果

vendor_name

Australia Bike Retailer

Snowflake
クエリ
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;
結果

VENDOR_NAME

Australia Bike Retailer

If/Elseステートメントの変換

If/Elseステートメントはさまざまな方法で処理できます。クエリ内で条件を許可するselect内で CASE EXPRESSION を使用して、JavaScriptまたは SQL に変換できます。JavaScript変換は非常に簡単ですが、Caseステートメントは一見するとそれほど明白ではないかもしれません。

Transact-SQL
クエリ
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;
結果

has_active_flag

NO

Snowflake
クエリ
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;
結果

HAS_ACTIVE_FLAG

NO

ネストされたステートメント

For nested statements, the structured programming is being transformed to a single query. The statements in the control-of-flow are going to be nested in table structures to preserve the execution order.

注釈

CASE EXPRESSIONS はステートメントごとに1つの値しか返せません

注釈

どちらのプログラミングパラダイムでも、次のコードは機能的に等価です。

構造化プログラミング
 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
結果

AccountNumber

LITWARE0001

SELECTs による条件変数

条件ステートメント内での変数定義と割り当ては、やや問題になりがちです。というのも、コードのさらに下にある変数への参照は、その変数が最後に変更された場所を知っていなければならないからです。それだけでなく、参照が別の条件ステートメント内にある場合、その変数への以前の既知の割り当てを参照する何らかのリダイレクトが必要です。

これは、入力コードに見られる入れ子や複雑なクエリによって悪化します。そのため、これらのパターンが見つかった場合は、特定の EWI が追加されます。

次のシナリオでは、最初の IF ステートメントは、内容が十分に単純なので、問題なく変換できます。2番目と3番目の IF ステートメントは、SELECT を通して変数割り当て以外のステートメントがあるため、現時点ではサポートされていないためコメントアウトされています。

SQL Server
クエリ
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
結果

RESULT

10

Snowflake
クエリ
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
;
結果

RESULT

10

変数を割り当てて返す

In this simple pattern, there is a variable declaration, then, that variable is set using a SELECT statement and finally returned. This is going to be migrated to a Common Table Expression to keep the original behavior.

SQL Server
クエリ
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;
結果

結果

1583978.2263

Snowflake
クエリ
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;
結果

RESULT

1583978.2263

複数の関数呼び出し

この特定のパターンでは、明らかなクエリはありませんが、同じ変数に対して複数の関数が呼び出され、最後にその変数が返されます。Snowflakeは関数内でのクエリしかサポートしていないため、このブロックの解決策は、Selectに追加して内部で呼び出しをネストし、戻り値がソース上の値と同じであることを確認することになります。

SQL Server
クエリ
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;
結果

名前

USA Car Retailer

Snowflake
クエリ
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;
結果

NAME

USA Car Retailer

複数の IF 条件に基づいて変数を増やし、その値を返す

このパターンでは、複数の IF 条件を使って変数が変更(この場合は増加)されます。最初に変数のセットが初期化され、結果変数を増やすかどうかを決定するために使用されます。最後に、結果変数が返されます。

SQL Server
クエリ
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;
結果

結果

473.1415

Snowflake
クエリ
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;
結果

RESULT

473.1415

2つ以上の RETURN ステートメント

このパターンでは、CASE 式で実行される最後のステートメントのように、コードの流れを断ち切るreturn句を含む IF ブロックが本文の最後に追加されます。

基本ケース

この特別なシナリオでは、条件 RETURN ステートメントと最終 RETURN ステートメントの間にロジックがないため、すべての本文は単一の CASE EXPRESSION にマッピングされます。

SQL Server
クエリ
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;
結果

結果

1

Snowflake
クエリ
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;
結果

RESULT

1

共通テーブル式

Common table expressions will be kept as in the original code, and they are going to be concatenated with the generated ones. SnowConvert AI is able to identify first all the original COMMON TABLE EXPRESSION names to avoid generating duplicated names.

SQL Server
クエリ
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;
結果

結果

3689

Snowflake
クエリ
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;
結果

RESULT

3689

JavaScript UDFs に変換

複数のステートメントがあり、関数がデータベースにアクセスしない場合は、機能の等価性を維持しながら JavaScript 関数に変換できます

SQL Server
クエリ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;
クエリ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;
結果1

DATE

2021

結果2

CleanChargeCode

16

Snowflake
クエリ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;
クエリ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;
結果1

DATE

2021.0

結果2

CLEANCHARGECODE

16

既知の問題

警告

ユーザー定義関数を使用して、データベースの状態を変更するアクションを実行することはできません

警告

ユーザー定義関数に、テーブルをターゲットとする OUTPUT INTO 句を含めることはできません

警告

ユーザー定義関数は、CURSOR を DECLARE、OPEN、FETCH、CLOSE、DEALLOCATE することはできません。カーソルを使用する必要がある場合は、ストアドプロシージャを使用してください。

警告

ユーザー定義関数は、データベースへの呼び出しが少なくとも1つある場合、WHILE のようなフロー制御ステートメントを実行できません

警告

ストアドプロシージャに変換された他のユーザー定義関数への参照を持つユーザー定義関数も、ストアドプロシージャに変換されます。

警告

User-defined functions that use @@ROWCOUNT are not supported in SQL and should be transformed to stored procedures to keep the functional equivalence.

警告

変数を自分自身に割り当てる SELECT ステートメントを持つユーザー定義関数は、Snowflakeではサポートされていません。SELECT @local_variable もご参照ください

サポートされていないすべてのケースについては、関連する EWIs と以下のパターンを確認して、推奨事項と可能な回避策を入手してください。

クエリに付随するif/elseステートメント以外の条件

次のシナリオでは、他のクエリと一緒に「whileステートメント」を使用します。この例の問題点は、メインセレクトの WITH 句の中でwhileステートメントを CTE に変換する方法がないことです。このため、同じロジックを維持するために、このステートメントを JavaScript プロシージャに変換せざるを得ません。

SQL Server
クエリ
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;
結果

結果

1007

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
        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;
結果

FOO

1007

行セットを反復処理して、独自の値を使用して変数を割り当てる

In the following example, the variable @names is used to concatenate multiple values from a column into one single string. The variable is updated on each iteration as shown, which is not supported by Snowflake UDFs. For this scenario, the function should be transformed into a procedure.

SQL Server

クエリ
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;
結果

名前

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

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;

警告

上記のシナリオについて、以下の制限を考慮してください。

  1. SELECTINSERTDELETEUPDATEMERGE などの DML クエリ内でのユーザー定義関数の呼び出しはすべて失敗します。これらのクエリ内でのストアドプロシージャの呼び出しは許可されていないためです。

  2. プロシージャの内部でユーザー定義関数を呼び出す場合は、その前に CALL キーワードを付ける必要があります。

  3. User-defined functions used in COMPUTED COLUMNS will fail during the execution.

関連 EWIs

  1. SSC-EWI-0067: UDF がSnowflakeプロシージャに変換され、クエリ内でのプロシージャの呼び出しがサポートされていません。

  2. SSC-EWI-0068 :ユーザー定義関数がSnowflakeプロシージャに変換されました。

  3. SSC-EWI-0073: 機能同等性レビュー保留中。

Snowflakeスクリプト UDF ( SCALAR )

SQL Serverスカラーユーザー定義関数から Snowflakeスクリプト UDFs への翻訳リファレンス。

Applies to
  • SQL Server

  • Azure Synapse Analytics

説明

SnowConvert は、すべての関数をストアドプロシージャに変換するのではなく、特定の条件を満たす場合に SQL Serverスカラーユーザー定義関数を直接 Snowflakeスクリプト UDFs ( SnowScript UDFs )に変換することをサポートしています。

Snowflakeスクリプト UDFs は、Snowflakeのプロシージャ言語構文(Snowscript)を使用して、 SQL UDF 本文内に記述されるユーザー定義関数です。変数、ループ、条件付きロジック、例外処理をサポートしています。

関数が SnowScript UDFs になる場合

SnowConvert は、各 SQL Server関数を分析し、適切なSnowflakeターゲットを自動的に決定します。関数は、データアクセス操作のないプロシージャロジック のみ を含む場合に、 SnowScript UDF になります。

サンプルソースパターン

単純な計算関数

データのクエリを行わずに計算を行う基本的なスカラー関数。

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;
結果

利益

50.00

Snowflake( SnowScript UDF )
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;
結果

PROFIT

50.00

条件付きロジックを持つ関数( IF/ELSE )

ビジネスロジックに IF/ELSE ステートメントを使用する関数。

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;
結果

DiscountRate

0.20

Snowflake( SnowScript UDF )
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;
結果

DISCOUNTRATE

0.20

WHILE ループを持つ関数

反復計算に WHILE ループを使用する関数。

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;
結果

FactorialResult

120

Snowflake( SnowScript UDF )
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;
結果

FACTORIALRESULT

120

文字列操作関数

ループや条件付きロジックを使用する複雑な文字列操作。

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;
結果

CleanPhone

5551234567

Snowflake( SnowScript UDF )
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;
結果

CLEANPHONE

5551234567

CASE ステートメントロジック

CASE 式を使用して分類を行う関数。

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;
結果

グレード

B

Snowflake( SnowScript UDF )
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;
結果

GRADE

B

Select Into variable assignment

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;
結果

CALCULATEPRICE(100, 3)

285

Snowflake( SnowScript UDF )
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;
$$;
結果

CALCULATEPRICE(100, 3)

285

既知の問題

警告

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

  • データベーステーブルにアクセスする

  • カーソルを使用する

  • 他の UDFs を呼び出す

  • 集計またはウィンドウ関数を含む

  • DML 操作を実行する( INSERT/UPDATE/DELETE )

  • 結果セットを返す

関連 EWIs

  1. SSC-EWI-0067: UDF がSnowflakeプロシージャに変換され、クエリ内でのプロシージャの呼び出しがサポートされていません。

  2. SSC-EWI-0068 :ユーザー定義関数がSnowflakeプロシージャに変換されました。

  3. SSC-EWI-0073: 機能同等性レビュー保留中。