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 は特定のステートメント( INSERT、 DELETE 、 UPDATE 、 SET 、 DECLARE など)や control-of-flow ブロック( IF...ELSE 、 WHILE など)を広く使用し、通常Snowflakeの SQL UDFs 定義との不一致や違反を表します。
制限事項¶
Transact UDFs は、他のデータベースエンジン(OracleやTeradataなど)にはない制限があります。これらの制限は、失敗の範囲を狭めることによって翻訳に役立ちます。つまり、避けるべきシナリオがあるということです。
以下に、SQL Serverが UDFs に対して持つ制限の一部を示します
UDFs はデータベースの状態を変更するアクションの実行には使用できません
ユーザー定義関数に、テーブルをターゲットとする OUTPUT INTO 句を含めることはできません
ユーザー定義関数は複数の結果セットを返すことはできません。複数の結果セットを返す必要がある場合は、ストアドプロシージャを使用します。
全リストはこちらのリンク ユーザー定義関数の作成(データベースエンジン)をご覧ください
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 < 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 < 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 |
共通テーブル式では、異なるステートメントはサポートされていません¶
UPDATE、INSERT、DELETE、ALTER、DROP の句は、区切り文字を使用して宣言した後でも、共通テーブル式の本文ではサポートされていません。このため、関数をストアドプロシージャとして動作するように変更することができます。
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¶
SSC-EWI-0040 :ステートメントがサポートされていません。
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 はターゲット言語として SQL と JavaScript のみをサポートします。
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ステートメント¶
関数本文で最もよく使われるステートメントは DECLARE と SET ステートメントです。デフォルト値のない 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 |
ネストされたステートメント¶
ネストされたステートメントの場合、構造化プログラミングは1つのクエリに変換されます。フロー制御内のステートメントは、実行順序を保持するためにテーブル構造の中にネストされます。
注釈
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 |
変数を割り当てて返す¶
この単純なパターンでは、変数宣言があり、SELECT ステートメントを使用して変数がセットされ、最後に返されます。これは、元の動作を維持するために、共通テーブル式 に移行する予定です。
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 |
共通テーブル式¶
共通テーブル式は元のコードで保持され、生成されたものと連結されます。SnowConvert AI は重複した名前を生成しないように、最初に元の COMMON TABLE EXPRESSION を識別できます。
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 のようなフロー制御ステートメントを実行できません
警告
ストアドプロシージャに変換された他のユーザー定義関数への参照を持つユーザー定義関数も、ストアドプロシージャに変換されます。
警告
SQL では、@@ROWCOUNT を使用するユーザー定義関数はサポートされていないため、機能的等価性を保つためにストアドプロシージャに変換する必要があります。
警告
変数を自分自身に割り当てる 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 |
行セットを反復処理して、独自の値を使用して変数を割り当てる¶
以下の例では、@names という変数を使って、列の複数の値を1つの文字列に連結しています。示されているように、変数は反復ごとに更新されますが、これは SnowFlake UDFs ではサポートされていません。このシナリオでは、関数を プロシージャ に変換する必要があります。
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;
警告
上記のシナリオについて、以下の制限を考慮してください。
SELECT、INSERT、DELETE、UPDATE、MERGEなどの DML クエリ内でのユーザー定義関数の呼び出しはすべて失敗します。これらのクエリ内でのストアドプロシージャの呼び出しは許可されていないためです。プロシージャの内部でユーザー定義関数を呼び出す場合は、その前に
CALLキーワードを付ける必要があります。COMPUTED COLUMNS で使用されるユーザー定義関数は実行中に失敗します。
関連 EWIs¶
SSC-EWI-0067: UDF がSnowflakeプロシージャに変換され、クエリ内でのプロシージャの呼び出しがサポートされていません。
SSC-EWI-0068 :ユーザー定義関数がSnowflakeプロシージャに変換されました。
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 assingment¶
Functions using simple select into for variable assignment.
SQL Server¶
CREATE FUNCTION dbo.CalculatePrice
(
@BasePrice DECIMAL(10, 2),
@Quantity INT
)
RETURNS DECIMAL(10, 2)
AS
BEGIN
DECLARE @Discount DECIMAL(5, 2);
DECLARE @Subtotal DECIMAL(10, 2);
DECLARE @FinalPrice DECIMAL(10, 2);
SELECT @Discount = CASE
WHEN @Quantity >= 10 THEN 0.15
WHEN @Quantity >= 5 THEN 0.10
ELSE 0.05
END,
@Subtotal = @BasePrice * @Quantity;
SET @FinalPrice = @Subtotal * (1 - @Discount);
RETURN @FinalPrice;
END;
結果¶
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¶
SSC-EWI-0067: UDF がSnowflakeプロシージャに変換され、クエリ内でのプロシージャの呼び出しがサポートされていません。
SSC-EWI-0068 :ユーザー定義関数がSnowflakeプロシージャに変換されました。
SSC-EWI-0073: 機能同等性レビュー保留中。