SnowConvert AI - SQL Server-Azure Synapse - プロシージャ¶
このセクションでは、構文とプロシージャの TSQL ステートメントをsnowflake javascriptに変換する方法を説明します。
Applies to
SQL Server
Azure Synapse Analytics
注釈
わかりやすくするため、出力コードの一部を省略しています。
1.CREATE PROCEDURE 翻訳¶
Snowflake CREATE PROCEDURE は SQL 構文で定義されており、その内部ステートメントは JavaScript で定義されています。
Transact¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE HumanResources.uspGetAllEmployees
@FirstName NVARCHAR(50),
@Age INT
AS
-- TSQL Statements and queries...
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE HumanResources.uspGetAllEmployees (FIRSTNAME STRING, AGE INT)
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
$$;
パラメーターの DATA TYPE¶
パラメーターデータ型はSnowflakeの同等のものに変換されます。データ型 もご参照ください。
EXEC ヘルパー¶
SnowFlake 環境でプロシージャのステートメントを実行できるようにするには、これらのステートメントを前処理して、ソース言語に固有のいくつかの変数に実行を反映するように調整する必要があります。
SnowConvert AI はサポートされているステートメントを自動的に翻訳し、 EXEC ヘルパーを使用します。このヘルパーは、これらのステートメントのネイティブ環境での実行をシミュレートする多くの変数にアクセスし、更新する機能を提供します。
例えば、移行されたプロシージャの中に、常に追加されるコードブロックがあります。次のセクションで、このコードの基本構造を説明します。私たちは常に、変換と私たちが必要とするヘルパーを合理化するための新しい改善方法を評価し、模索していることを心に留めておいてください。
構造¶
EXEC ヘルパーの基本構造は以下の通りです。
変数宣言セクション: ここでは、プロシージャ内のステートメントの実行に関連する値を格納するさまざまな変数またはオブジェクトを宣言します。これには、ステートメントによって影響を受ける行の数や、結果セット自体などの値が含まれます。
fixBind関数宣言: これは、バインドが日付型である場合にバインドを修正するための補助関数です。
EXEC 関数宣言: これはメインの EXEC ヘルパー関数です。実行するステートメント、バインド配列(基本的に実行によって変更される可能性があり、プロシージャの実行中データの永続性を必要とする変数またはパラメーター)、ERROR_HANDLERS を使用しなければならないかどうかを決定するnoCatchフラグ、ステートメントの実行中に例外が発生したときにカスタムコードを実行するためのcatchFunction関数を受け取ります。EXEC 関数の本文は非常に単純です。ステートメントを実行し、その実行によって生成されたすべての貴重なデータをすべてエラー処理ブロック内に格納します。
ERROR VARS: EXEC catchブロックは、
MESSAGE_TEXT、SQLCODE、SQLSTATE、PROC_NAMEおよびERROR_LINEなどのエラー変数のリストを設定します。これらの変数は、ユーザー定義関数から値を取得するために使用でき、 SQL Server ERROR_LINE、 ERROR_MESSAGE、 ERROR_NUMBER、 ERROR_PROCEDURE および ERROR_STATE 組み込み関数の動作をエミュレートします。これらの変数がすべて1つの値でセットされた後、UPDATE_ERROR_VARSユーザー定義関数は、SQL スコープでアクセスできるように、いくつかの環境変数をエラー値で更新します。
コード¶
次のコードブロックは、プロシージャ内の EXEC ヘルパーを表しています。
var _RS, ROW_COUNT, _ROWS, MESSAGE_TEXT, SQLCODE = 0, SQLSTATE = '00000', ERROR_HANDLERS, NUM_ROWS_AFFECTED, INTO;
var fixBind = function (arg) {
arg = arg == undefined ? null : arg instanceof Date ? arg.toISOString() : arg;
return arg;
};
var fetch = (count,rows,stmt) => (count && rows.next() && Array.apply(null,Array(stmt.getColumnCount())).map((_,i) => rows.getColumnValue(i + 1))) || [];
var EXEC = (stmt,binds = [],noCatch = false) => {
binds = binds ? binds.map(fixBind) : binds;
for(var stmt of stmt.split(";").filter((_) => _)) {
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]});
throw error;
}
}
};
単純な EXEC の例
これは、ストアドプロシージャ内で EXEC を呼び出す単純な例です
ソースコード
-- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_1
AS
EXECUTE('SELECT 1 AS Message');
GO
-- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_1
GO
期待されるコード
CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_1 ()
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 = 'dbo', 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(`SELECT 1 AS Message;`);
$$;
パラメーターを持つストアドプロシージャ内の EXEC
この例では、EXEC コマンドがストアドプロシージャ内にあり、パラメーター値を受け取ります
ソースコード
-- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_2
@p1 varchar(50) = N''
AS
EXEC ('SELECT ' + @p1);
GO
-- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_2 N'''Hello World!'''
GO
期待されるコード
CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_2 (P1 STRING DEFAULT '')
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
EXEC(`SELECT
${P1};`);
$$;
パラメーターを持つストアドプロシージャを呼び出す EXEC
この例では、EXEC は別のストアドプロシージャを呼び出し、パスはパラメーターを追加します
ソースコード
-- Additional Params: -t JavaScript
CREATE PROCEDURE dbo.EXEC_EXAMPLE_3
@p1 varchar(50) = N''
AS
EXEC EXEC_EXAMPLE_2 @p1
GO
-- =============================================
-- Example to execute the stored procedure
-- =============================================
EXECUTE dbo.EXEC_EXAMPLE_3 N'''Hello World!'''
GO
期待されるコード
CREATE OR REPLACE PROCEDURE dbo.EXEC_EXAMPLE_3 (P1 STRING DEFAULT '')
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
EXEC(`CALL EXEC_EXAMPLE_2(?)`,[P1]);
$$;
デフォルト値のパラメーター。¶
SqlServer では、プロシージャを呼び出すときにパラメーターが指定されない場合に備えて、デフォルト値を持つパラメーターが存在することがあります。
SQL Server¶
CREATE PROCEDURE PROC_WITH_DEFAULT_PARAMS1
@PARAM1 INT = 0, @PARAM2 INT = 0, @PARAM3 INT = 0, @PARAM4 INT = 0
AS
BEGIN
.
.
.
END
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC_WITH_DEFAULT_PARAMS1(param1 int default 0, param2 int default 0, param3 int default 0, param4 int default 0)
RETURNS TABLE()
LANGUAGE SQL
EXECUTE AS CALLER
AS
$$
.
.
.
$$;
CALL PROC_WITH_DEFAULT_PARAMS1(param2 => 10, param4 => 15);
CURSOR ヘルパー¶
CREATE OR REPLACE PROCEDURE PROC1()
RETURNS STRING
LANGUAGE JAVASCRIPT
EXECUTE AS CALLER
AS
$$
var CURSOR = function (stmt, binds) {
var statementObj, result_set, total_rows, isOpen = false, self = this, row_count;
this.CURRENT = new Object;
var fetch = (count,rows,stmt) => (count && rows.next() && Array.apply(null,Array(stmt.getColumnCount())).map((_,i) => rows.getColumnValue(i + 1))) || [];
var fixBind = function (arg) {
arg = arg == undefined ? null : arg instanceof Date ? formatDate(arg) : arg;
return arg;
};
this.OPEN = function(openParameters) {
if (result_set == undefined) {
try {
if (openParameters) binds = openParameters;
if (binds instanceof Function) binds = binds();
var finalBinds = binds && binds.map(fixBind);
var finalStmt = stmt instanceof Function ? stmt() : stmt;
statementObj = snowflake.createStatement({
sqlText : finalStmt,
binds : finalBinds
});
result_set = statementObj.execute();
total_rows = statementObj.getRowCount();
isOpen = true;
row_count = 0;
} catch(error) {
RAISE(error.code,"error",error.message);
}
else {
isOpen = true;
}
}
return this;
};
this.CURSOR_ROWS = function () {
return total_rows;
};
this.FETCH_STATUS = function() {
if(total_rows > row_count)
return 0;
else
return -1;
};
this.FETCH_NEXT = function() {
self.res = [];
if (isOpen) {
self.res = fetch(total_rows,result_set,statementObj);
if (self.res)
row_count++;
}
return self.res && self.res.length > 0;
};
this.INTO = function () {
return self.res;
};
this.CLOSE = function () {
isOpen = false;
};
this.DEALLOCATE = function() {
this.CURRENT = row_count = result_set_table = total_rows = result_set = statementObj = self = undefined;
};
};
var COL1, COL2;
var sql_stmt = ``;
let c = new CURSOR(`SELECT COL1, COL2 FROM TABLE1;`,() => []);
c.OPEN();
c.FETCH_NEXT();
[COL1, COL2] = c.INTO();
while ( c.FETCH_STATUS()) {
sql_stmt = `INSERT INTO TABLE2 (COL1, COL2) VALUES (` + COL1+ `, ` + COL2 + `)`;
snowflake.createStatement({
sqlText : sql_stmt
}).execute();
}
c.CLOSE();
c.DEALLOCATE();
return 'sucess';
$$;
Insert Into EXEC ヘルパー¶
Insert into Execヘルパーは、Insert insertIntoTemporaryTable(sql) という関数を生成します。この関数は、INSERT INTO TABLE_NAME EXEC(...) を TSQL からSnowflakeへ変換して、データを仮テーブルに挿入し、それを元のInsertに再追加することで、元のステートメントからの動作を模倣することを可能にします。
このステートメントのコードがどのように変更されるかについての情報は、Insert Into Execのセクションを参照してください
注釈
この INSERT INTO EXEC 用に生成されたコードは、内部に複数のクエリを含む EXECUTE ステートメントを処理する際にパフォーマンス上の問題が発生する可能性があります。
function insertIntoTemporaryTable(sql) {
var table = "SnowConvertPivotTemporaryTable";
return EXEC('CREATE OR REPLACE TEMPORARY TABLE ${table} AS ${sql}');
}
insertIntoTemporaryTable(`${DBTABLES}`)
EXEC(`INSERT INTO MYDB.PUBLIC.T_Table SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
LIKE ヘルパー¶
Like式がプロシージャ内に見つかった場合、例えば
CREATE PROCEDURE ProcedureLike @VariableValue VARCHAR(50) AS
BEGIN
IF @VariableValue like '%c%'
BEGIN
Select AValue from ATable;
END;
END;
プロシージャの内部はjavascriptに変換されるので、Like式はエラーを投げます。これを避け、機能を維持するために、Like式が見つかった場合、プロシージャの最初に関数が追加されます。
function LIKE(expr,pattern,esc,cs) {
function fixPattern(pattern,esc) {
const specials = '/.*+?|(){}[]\\'.split('');
var newPattern = "";
var fix = (c) => specials.includes(c) ? '\\' + c : c;
for(var i = 0;i < pattern.length;i++) {
var c = pattern[i];
if (c === esc) {
newPattern += pattern[i + 1]
i++
} else if (c === '%') {
newPattern += ".*?"
} else if (c === '_') {
newPattern += "."
} else if (c === '[' || ']') {
newPattern += c
} else newPattern += fix(c)
}
return newPattern;
}
return new RegExp(`^${fixPattern(pattern,esc)}$`,cs ? '' : 'i').exec(expr) != null;
}
この関数を使えば、SQLのLike式の機能を複製することができます。どのように使えるか、様々なケースを見てみましょう
-- Additional Params: -t JavaScript
CREATE PROCEDURE ProcedureLike @VariableValue VARCHAR(50) AS
BEGIN
IF @VariableValue like '%c%'
BEGIN
Select AValue from ATable;
END;
IF @VariableValue not like '%c%'
BEGIN
Select BValue from BTable;
END;
IF @VariableValue like '%c!%%' escape '!'
BEGIN
Select CValue from CTable;
END;
END;
最後のコードには、通常のlikeとnot like、およびエスケープ付きのlikeがあります。変換は以下のようになります
CREATE OR REPLACE PROCEDURE ProcedureLike (VARIABLEVALUE STRING)
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
if (LIKE(VARIABLEVALUE,`%c%`)) {
{
EXEC(` Select
AValue
from
ATable`);
}
}
if (!LIKE(VARIABLEVALUE,`%c%`)) {
{
EXEC(` Select
BValue
from
BTable`);
}
}
if (LIKE(VARIABLEVALUE,`%c!%%`,`!`)) {
{
EXEC(` Select
CValue
from
CTable`);
}
}
$$;
Likeは関数呼び出しに変換されることに注意してください
LIKE(VARIABLEVALUE,`%c%`)
!LIKE(VARIABLEVALUE,`%c%`)
LIKE(VARIABLEVALUE,`%c!%%`,`!`)
関数 LIKE が受け取るパラメーターは以下の通りです。
評価される式。
比較のパターン
エスケープ文字がある場合、これはオプションのパラメーターです。
Selectヘルパー¶
スカラー値を変数にセットする必要がある場合、SELECT という関数を生成します
-- Additional Params: -t JavaScript
CREATE PROCEDURE MAX_EMPLOYEE_ID
AS
BEGIN
DECLARE @VARIABLE INT
SET @VARIABLE = (SELECT MAX(EMPLOYEE_ID) FROM EMPLOYEES);
RETURN @VARIABLE
END;
この場合、SELECT ヘルパーを使って以下のコードを生成します
CREATE OR REPLACE PROCEDURE MAX_EMPLOYEE_ID ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let VARIABLE;
VARIABLE = EXEC(`SELECT
MAX(EMPLOYEE_ID) FROM
EMPLOYEES`);
return VARIABLE;
$$;
SELECT ヘルパーは、クエリから取得した値をローカル値に挿入するためにも使えます。このヘルパーは、SQL Server SELECT @local_variable と同じ動作をサポートするように特別に設計されました。args パラメーターは、select内のすべてのローカル変数に適用される各操作を表します。SELECT @Variableも参照してください。例:
-- Additional Params: -t JavaScript
CREATE PROCEDURE [PROCEDURE1] AS
DECLARE @VAR1 int;
DECLARE @VAR2 int;
select @VAR1 = col1 + col2, @VAR2 += col1 from table1;
GO
この場合、変数の割り当ては、SQL Serverの動作をエミュレートするために JavaScript ラムダに翻訳されます。
CREATE OR REPLACE PROCEDURE PROCEDURE1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let VAR1;
let VAR2;
SELECT(` col1 + col2,
col1
from
table1`,[],(value) => VAR1 = value,(value) => VAR2 += value);
$$;
RAISERROR ヘルパー¶
このヘルパーは、ソースコード中に RAISERROR 呼び出しの使用がある場合に生成されます。例:
var RAISERROR = (message,severity,state) => {
snowflake.execute({
sqlText : `SELECT UPDATE_ERROR_VARS_UDF(?,?,?)`,
binds : [message,severity,state]
});
var msg = `Message: ${message}, Level: ${severity}, State: ${state}`;
throw msg;
};
RAISERROR は、エラーメッセージ、重大度、および状態の値を環境変数として保存するために、UPDATE_ERROR_VARS_UDF を実行します。これは、ERROR 組み込み関数のいずれかを呼び出して使用する必要がある場合に備えます。最後に、SQL Serverと同じ形式でエラーメッセージが投げられます。
アイデンティティ関数ヘルパー¶
このヘルパーは、アイデンティティ関数 がプロシージャ内のSelect Intoで使用されるたびに生成されます。
var IdentityHelper = (seed,increment) => {
var sequenceString = "`CREATE OR REPLACE SEQUENCE SnowConvert_Temp_Seq START = ${seed} INCREMENT = ${increment}`";
return EXEC(sequenceString);
このヘルパーのパラメーターは元の関数と同じで、TSQL のアイデンティティ関数の動作を模倣するシーケンスを生成するために作成されます。元のコードへの変更は次のとおりです。
ソースコードにあるのと同じパラメーターを使用した、IdentityHelper 関数への追加メソッド呼び出し。
そして、シーケンス内の次の値を取得するための関数設計を IDENTITY_UDF に呼び出します。
IdentityHelper(1,1)
EXEC(`CREATE TABLE PUBLIC.department_table3 AS SELECT IDENTITY_UDF() /*** MSC-WARNING - MSCEWI1046 - 'identity' FUNCTION MAPPED TO 'IDENTITY_UDF', FUNCTIONAL EQUIVALENCE VERIFICATION PENDING ***/ as Primary_Rank
from PUBLIC.department_table`);
TSQL のように、パラメーターが与えられていない場合は、(1,1)がデフォルト値になります。
CALL プロシージャヘルパー¶
このヘルパーは、以前はユーザー定義関数であったが、現在は翻訳プロセスの結果としてプロシージャになっているものへの呼び出しがあるたびに生成されます。
var CALL = (sql,binds = [],...args) => {
EXEC("CALL " + sql,binds);
_ROWS.next();
return (_ROWS.getColumnValue(1))[0];
};
このヘルパーの目的は、プロシージャをあたかも関数のように呼び出すために必要なロジックをカプセル化することです。
プロシージャは SELECT のようなクエリの中で呼び出すことができないため、この機能には制限があることに留意してください。
FooSelfAssign(@PAR INT) がプロシージャに翻訳されたと仮定した場合の使用例:
// Input code
DECLARE @VAR1 INT = FooSelfAssign(1);
DECLARE @VAR4 INT = FooSelfAssign(FooSelfAssign(FooSelfAssign(FooSelfAssign(4))));
// Output code
let VAR1 = CALL(`FooSelfAssign(1)`)
let VAR4 = CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(?)`,[CALL(`FooSelfAssign(4)`)])])]);
VAR1 の翻訳は非常に簡単ですが、VAR4 の場合、CALL の一番外側には、CALLs の残りの部分がバインディングとしてリストに含まれていることに注意してください。
後続の各 CALL は、別の CALL 内に含まれている場合、バインディングに翻訳されます。
2.変数¶
DECLARE @Variable¶
SQL Server¶
DECLARE @product_list VARCHAR(MAX) = ' ';
DECLARE @Variable1 AS VARCHAR(100), @Variable2 AS VARCHAR(100);
Snowflake¶
let PRODUCT_LIST = ` `;
let VARIABLE1;
let VARIABLE2;
DECLARE @Variable Table¶
この場合、DECLARE は変数テーブルを宣言するために使用されています。例を見てみましょう。
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
DECLARE @VariableNameTable TABLE
(
[Col1] INT NOT NULL,
[Col2] INT NOT NULL
);
INSERT INTO @VariableNameTable Values(111,222);
Select * from @VariableNameTable;
END
Exec PROC1;
このコードをSQL Serverで実行すると、次のような結果が得られます
col1 |
col2 |
|---|---|
111 |
222 |
では、Snowflakeの変換を見てみましょう
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
{
EXEC(`CREATE OR REPLACE TEMPORARY TABLE T_VariableNameTable
(
Col1 INT NOT NULL,
Col2 INT NOT NULL
)`);
EXEC(`INSERT INTO T_VariableNameTable Values(111,222)`);
EXEC(`Select
*
from
T_VariableNameTable`);
}
EXEC(`CALL PROC1()`);
$$;
61 行から 67 行までがプロシージャ内のステートメントの結果であることに注意してください。
宣言変数テーブルが仮テーブルになります。名前内の文字@がT_に置き換えられていることに注意してください。
このコードをSnowflakeで実行しても、結果は得られず、nullが表示されるだけです。これは、最後のSelectが EXEC ヘルパー内にあるためです。では、テーブルがそこにあることをどうやって知るのでしょうか?
EXEC のプロシージャ内で一時テーブルとして作成されたため、プロシージャの外部でそのテーブルに対してSelectを実行できます。
Select * from PUBLIC.T_VariableNameTable;
このステートメントを実行すると、次のような結果が得られます
col1 |
col2 |
|---|---|
111 |
222 |
SET @Variable¶
今のところ、セット変数は右辺にある式によって変換されます。
式に変換がある場合は、JavaScript の相当するものに変換されます。
例
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
SET @product_list2 = '';
SET @product_list = '';
SET @var1 += '';
SET @var2 &= '';
SET @var3 ^= '';
SET @var4 |= '';
SET @var5 /= '';
SET @var6 %= '';
SET @var7 *= '';
SET @var8 -= '';
SET @ProviderStatement = 'SELECT * FROM TABLE1
WHERE COL1 = '+@PARAM1+ ' AND COL2 = ' + @LOCALVAR1;
SET @NotSupported = functionValue(a,b,c);
END
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
PRODUCT_LIST2 = ``;
PRODUCT_LIST = ``;
VAR1 += ``;
VAR2 &= ``;
VAR3 ^= ``;
VAR4 |= ``;
VAR5 /= ``;
VAR6 %= ``;
VAR7 *= ``;
VAR8 -= ``;
PROVIDERSTATEMENT = `SELECT
*
FROM
TABLE1
WHERE
COL1 = ${PARAM1}
AND COL2 = ${LOCALVAR1};`;
NOTSUPPORTED = SELECT(` functionValue(a,b,c) !!!RESOLVE EWI!!! /*** SSC-EWI-0073 - PENDING FUNCTIONAL EQUIVALENCE REVIEW FOR 'functionValue' NODE ***/!!!`);
$$;
例でわかるように、変数 NOTSUPPORTED の値は、当分の間変換されないので、コメントされています。これは、まだ変換が完了していないことを意味します。
他の種類のセットについてはコメントされます。例えば次の通りです
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1
AS
BEGIN
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
;
SET NOCOUNT ON
;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
;
SET NOCOUNT OFF
;
END
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED*/
;
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET NOCOUNT ON*/
;
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED*/
;
/*** SSC-EWI-0040 - THE 'SET' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*SET NOCOUNT OFF*/
;
$$;
SELECT @Variable¶
今のところ、SELECT @variable は単純なselectに変換され、変数の割り当ては削除され、演算子の右側に式が残ります。select内のローカル変数の割り当て操作は、arrow 関数に置き換えられます。この関数は、SQL Server でローカル変数の割り当て中に行われた操作と同じ動作を表します。
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE PROC1 AS
DECLARE @VAR1 int;
DECLARE @VAR2 int;
SELECT @VAR1 = COL1 + COL2, @VAR2 = COL3 FROM TABLE1;
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE PROC1 ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let VAR1;
let VAR2;
SELECT(` COL1 + COL2,
COL3
FROM
TABLE1`,[],(value) => VAR1 = value,(value) => VAR2 = value);
$$;
3.ステートメント翻訳¶
SELECT¶
基本的な形式¶
基本的な SELECT 形式にはバインディングがないため、この翻訳は、1つのパラメーターで EXEC ヘルパー関数の呼び出しを作成することを意味しています。例:
-- Source code:
SELECT * FROM DEMO_TABLE_1;
// Translated code:
EXEC(`SELECT * FROM DEMO_TABLE_1`);
IF¶
SQL Server¶
IF Conditional_Expression
-- SQL Statement
ELSE IF Conditiona_Expression2
-- SQL Statement
ELSE
-- SQL Statement
Snowflake¶
if (Conditional_Expression) {
// SQL Statement
} else if (Conditional_Expression2) {
// SQL Statement
} else{
// SQL Statement
}
WHILE¶
SQL Server¶
WHILE ( Conditional_Expression )
BEGIN
-- SQL STATEMENTS
END;
Snowflake¶
while ( Conditional_Expression )
{
// SQL STATEMENTS
}
EXEC / EXECUTE¶
SQL Server¶
-- Execute simple statement
Exec('Select 1');
-- Execute statement using Dynamic Sql
Exec('Select ' + @par1 + ' from [db].[t1]');
-- Execute Procedure with parameter
EXEC db.sp2 'Create proc [db].[p3] AS', @par1, 1
Snowflake¶
-- Execute simple statement
EXEC(`Select 1`);
-- Execute statement using Dynamic Sql
EXEC(`Select ${PAR1} from MYDB.db.t1`);
-- Execute Procedure with parameter
EXEC(`CALL db.sp2(/*** SSC-EWI-0038 - THIS STATEMENT MAY BE A DYNAMIC SQL THAT COULD NOT BE RECOGNIZED AND CONVERTED ***/
'Select * from MYDB.db.t1', ?, 1, Default)`,[PAR1]);
THROW¶
THROW の変換は、エラーを受け取るcatchブロックが元のステートメントで指定された情報にアクセスできるようにします。
SQL Server¶
-- Case 1
THROW
-- Case 2
THROW 123, 'The error message', 1
-- Case 3
THROW @var1, @var2, @var3
Snowflake¶
// Case 1
throw {};
// Case 2
throw { code: 123, message: "The error message", status: 1 };
// Case 3
throw { code: VAR1, message: VAR2, status: VAR3 };
RAISERROR¶
SQL Server RAISERROR 関数は、Snowflakeではサポートされていません。 SnowConvert AI は、オリジナルの動作をエミュレートするヘルパーを生成するために、すべての使用法を識別します。例:
SQL Server¶
-- Additional Params: -t JavaScript
CREATE OR ALTER PROCEDURE RAISERRORTEST AS
BEGIN
DECLARE @MessageTXT VARCHAR = 'ERROR MESSAGE';
RAISERROR (N'E_INVALIDARG', 16, 1);
RAISERROR ('Diagram does not exist or you do not have permission.', 16, 1);
RAISERROR(@MessageTXT, 16, 1);
END
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE RAISERRORTEST ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let MESSAGETXT = `ERROR MESSAGE`;
RAISERROR("E_INVALIDARG","16","1");
RAISERROR("Diagram does not exist or you do not have permission.","16","1");
RAISERROR(MESSAGETXT,"16","1");
$$;
BREAK/CONTINUE¶
break/continue変換は、コードの流れを確実に止めたり、別のブロックに続けたりします。
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE ProcSample
AS
BEGIN
IF @@ROWCOUNT > 0
Continue;
ELSE
BREAK;
END
Snowflake¶
CREATE OR REPLACE PROCEDURE ProcSample ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
if (ROW_COUNT > 0) {
continue;
} else {
break;
}
$$;
INSERT INTO EXEC¶
INSERT INTO [Table] EXEC(...) ステートメントはSnowflakeではサポートされていないため、コードが若干変更されています。これにより、数行のコードを追加することで動作を複製できます。
最初に追加された行は、
insertIntoTemporaryTableへの呼び出しで、EXEC内の引数から抽出されたコードが、結果セットを仮テーブルに挿入します。関数の詳細情報については、Insert Into EXEC ヘルパーセクションをご覧ください。InsertのExecはコードから削除され、EXEC の結果を仮テーブルから取り出すクエリが実行されます。
SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable
最後に追加された行は、追加された仮テーブルの DROP TABLE ステートメントです。
DROP TABLE SnowConvertPivotTemporaryTable
SQL Server¶
INSERT INTO #Table1
EXEC ('SELECT
Table1.ID
FROM Population');
INSERT INTO #Table1
EXEC (@DBTables);
Snowflake¶
insertIntoTemporaryTable(`SELECT Table1.ID FROM MYDB.PUBLIC.Population)
EXEC(`INSERT INTO MYDB.PUBLIC.T_Table1 SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
insertIntoTemporaryTable(`${DBTABLES}`)
EXEC(`INSERT INTO MYDB.PUBLIC.T_Table1 SELECT * FROM MYDB.PUBLIC.SnowConvertPivotTemporaryTable`);
EXEC(`DROP TABLE SnowConvertPivotTemporaryTable`)
BEGIN TRANSACTION¶
BEGIN TRANSACTION はSnowflakeの BEGIN コマンドに変換され、EXEC ヘルパー呼び出しに挿入されます。
ヘルパーは結果の BEGIN を実際に実行する役割を担います。
SQL Server¶
-- Input code
BEGIN TRAN @transaction_name;
Snowflake¶
// Output code
EXEC(`BEGIN`, []);
COMMIT TRANSACTION¶
COMMIT TRANSACTION はSnowflakeの COMMIT コマンドに変換され、EXEC ヘルパー呼び出しに挿入されます。
ヘルパーは結果の COMMIT を実際に実行する役割を担います。
SQL Server¶
-- Input code
COMMIT TRAN @transaction_name;
Snowflake¶
// Output code
EXEC(`COMMIT`, []);
ROLLBACK TRANSACTION¶
ROLLBACK TRANSACTION はSnowflakeの ROLLBACK コマンドに変換され、EXEC ヘルパー呼び出しに挿入されます。
ヘルパーは結果の ROLLBACK を実際に実行する役割を担います。
SQL Server¶
-- Input code
ROLLBACK TRAN @transaction_name;
Snowflake¶
// Output code
EXEC(`ROLLBACK`, []);
WAITFOR DELAY¶
WAITFOR DELAY 句はSnowflakeの SYSTEM$WAIT 関数に変換されます。DELAY の time\ o\pass パラメーターは、SYSTEM$WAIT 関数のパラメーターとして使用するために秒数に変換されます。
WAITFOR 句の他のバリアントはSnowflakeではサポートされていないため、対応するメッセージが表示されます。
SQL Server¶
-- Input code
1) WAITFOR DELAY '02:00';
2) WAITFOR TIME '13:30';
3) WAITFOR (RECEIVE TOP (1)
@dh = conversation_handle,
@mt = message_type_name,
@body = message_body
FROM [eqe]), TIMEOUT 5000;
Snowflake¶
// Output code
1) EXEC(`SYSTEM$WAIT(120)`,[]);
2) /*** SSC-EWI-0040 - THE 'WAIT FOR' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*WAITFOR TIME '13:30'*/
;
3) /*** SSC-EWI-0040 - THE 'WAIT FOR' CLAUSE IS NOT SUPPORTED IN SNOWFLAKE ***/
/*WAITFOR (RECEIVE TOP (1)
@dh = conversation_handle,
@mt = message_type_name,
@body = message_body
FROM [eqe]), TIMEOUT 5000*/
;
3.カーソル¶
CURSORS はSnowflakeではサポートされていないため、 SnowConvert AI はその機能を、ターゲットプラットフォームでオリジナルの動作をエミュレートする JavaScript ヘルパーにマップします。例:
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE [procCursorHelper] AS
DECLARE vendor_cursor CURSOR FOR
SELECT VendorID, Name
FROM Purchasing.Vendor
WHERE PreferredVendorStatus = 1
ORDER BY VendorID;
GO
Snowflake¶
CREATE OR REPLACE PROCEDURE procCursorHelper ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
var VENDOR_CURSOR = new CURSOR(`SELECT
VendorID,
Name
FROM
Purchasing.Vendor
WHERE
PreferredVendorStatus = 1
ORDER BY VendorID`,[],false);
$$;
DECLARE CURSOR¶
SQL Server¶
DECLARE myCursor1 CURSOR FOR SELECT COL1 FROM TABLE1
Snowflake¶
let myCursor1 = new CURSOR(`SELECT COL1 FROM TABLE1`,() => []);
OPEN¶
SQL Server¶
OPEN myCursor1
OPEN GLOBAL myCursor2
Snowflake¶
myCursor1.OPEN();
myCursor2.OPEN()
FETCH¶
SQL Server¶
DECLARE @VALUE1 INT
FETCH NEXT FROM myCursor1 into @VALUE1
Snowflake¶
var VALUE1;
myCursor1.FETCH_NEXT();
VALUE1 = myCursor1.INTO();
CLOSE¶
SQL Server¶
CLOSE myCursor1
CLOSE GLOBAL myCursor2
Snowflake¶
myCursor1.CLOSE()
myCursor2.CLOSE()
DEALLOCATE¶
SQL Server¶
DEALLOCATE myCursor1
DEALLOCATE GLOBAL myCursor2
Snowflake¶
myCursor1.DEALLOCATE()
myCursor2.DEALLOCATE()
@@FETCH_STATUS¶
SQL Server¶
@@FETCH_STATUS
Snowflake¶
myCursor1.FETCH_STATUS()
@@CURSOR_ROWS¶
SQL Server¶
@@CURSOR_ROWS
Snowflake¶
myCursor1.FETCH_STATUS()
4.式¶
バイナリ操作¶
SQL Server¶
SET @var1 = 1 + 1;
SET @var1 = 1 - 1;
SET @var1 = 1 / 1;
SET @var1 = 1 * 1;
SET @var1 = 1 OR 1;
SET @var1 = 1 AND 1;
Snowflake¶
VAR1 = 1 + 1;
VAR1 = 1 - 1;
VAR1 = 1 / 1;
VAR1 = 1 * 1;
VAR1 = 1 || 1;
VAR1 = 1 && 1;
条件¶
SQL Server¶
@var1 > 0
@var1 = 0
@var1 < 0
@var1 <> 0
Snowflake¶
VAR1 > 0
VAR1 = 0
VAR1 < 0
VAR1 != 0
NULL 述語¶
SQL Server¶
@var1 is null
@var2 is not null
Snowflake¶
VAR1 == null
VAR2 != null
5.ラベルとGoto¶
ラベル は JavaScript では SQL Serverと同じ動作はしません。動作をシミュレートするために、これらは 関数 に変換されています。その使用は、ラベルのすべてのロジックを含む生成関数の呼び出しに置き換えられています。例:
ソースコード¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE [procWithLabels]
AS
SUCCESS_EXIT:
SET @ErrorStatus = 0
RETURN @ErrorStatus
ERROR_EXIT:
RETURN @ErrorStatus
Snowflake¶
CREATE OR REPLACE PROCEDURE procWithLabels ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
SUCCESS_EXIT();
ERROR_EXIT();
function SUCCESS_EXIT() {
ERRORSTATUS = 0;
return ERRORSTATUS;
}
function ERROR_EXIT() {
return ERRORSTATUS;
}
$$;
上の例にあるように、ソースコードのラベルであった関数宣言は、コードをすっきりさせるためにコードの末尾に置かれます。
GOTO も JavaScript には存在しないコマンドです。その動作をシミュレートするために、それらの使用は、returnステートメントに先行して、参照されている関数(ラベル)への呼び出しに変換されています。例:
SQL Server¶
-- Additional Params: -t JavaScript
CREATE PROCEDURE [procWithLabels]
AS
DECLARE @ErrorStatus int = 0;
IF @ErrorStatus <> 0 GOTO ERROR_EXIT
SUCCESS_EXIT:
SET @ErrorStatus = 0
RETURN @ErrorStatus
ERROR_EXIT:
RETURN @ErrorStatus
Snowflake¶
CREATE OR REPLACE PROCEDURE procWithLabels ()
RETURNS STRING
LANGUAGE JAVASCRIPT
COMMENT = '{"origin":"sf_sc","name":"snowconvert","version":{"major":1, "minor":0},{"attributes":{"component":"transact"}}'
EXECUTE AS CALLER
AS
$$
// SnowConvert AI Helpers Code section is omitted.
let ERRORSTATUS = 0;
if (ERRORSTATUS != 0) {
return ERROR_EXIT();
}
SUCCESS_EXIT();
ERROR_EXIT();
function SUCCESS_EXIT() {
ERRORSTATUS = 0;
return ERRORSTATUS;
}
function ERROR_EXIT() {
return ERRORSTATUS;
}
$$;
上の例でわかるように、return が関数呼び出しに追加されています。これは、SQL Serverが GOTO で行っているように、コードの流れを止めるためです。