I'm trying to convert the below Azure SQL stored procedure to Snowflake. But I couldn't find an alternative for the EXEC statement yet:
CREATE PROC SAMPLE_PROC
AS
BEGIN
DECLARE #BusinessUnitKey INT=(SELECT BusinessUnitKey FROM BusinessUnit WHERE BusinessUnitName='ABC') ;
DECLARE #LoadDate DATETIME= (SELECT Cast(GETUTCDATE() as Date)) ;
DECLARE #DataLoadLogKey INT = (
SELECT MAX(DataLoadLogKey)
FROM DataLoadLog
WHERE BusinessUnitKey = #BusinessUnitKey
)
,#TableName VARCHAR(100) = 'ProductType'
,#StoredProcName VARCHAR(100) = (object_name(##procid))
,#StarDateTime DATETIME = #LoadDate
,#EndDateTime DATETIME = NULL
,#Status VARCHAR(100) = 'In Progress'
,#LoadDescription VARCHAR(1000) = 'Loading Data' ;
EXEC dbo.usp_procedure #DataLoadLogKey = #DataLoadLogKey
,#TableName = #TableName
,#StoredProcName = #StoredProcName
,#StarDateTime = #StarDateTime
,#EndDateTime = NULL
,#Status = #Status
,#LoadDescription = #LoadDescription ;
END;
Could anyone provide the corresponding execute statement in Snowflake?
Take a look at the Working with Stored Procedures in documentation.
This is a rough stub that should compile.
I cant test the code, as I dont have ddl for your tables or data to validate, but this should give you a good start.
Best Regards.
CREATE OR REPLACE PROCEDURE SAMPLE_PROC()
returns VARCHAR not null
language javascript
as
$$
var businessUnitKey , loadDate, dataLoadLogKey, sql, statement, rs, message ;
message= "FAILED";
// get business unit key
sql = `SELECT BusinessUnitKey FROM BusinessUnit WHERE BusinessUnitName='ABC'`;
statement = snowflake.createStatement({sqlText: sql});
result_set = statement.execute();
while (result_set.next()) {
businessUnitKey = result_set.getColumnValue(1);
}
// get load date
sql = `SELECT Cast(SYSDATE() as Date)`;
statement = snowflake.createStatement({sqlText: sql});
result_set = statement.execute();
while (result_set.next()) {
loadDate = result_set.getColumnValue(1);
}
//return loadDate
sql = `SELECT MAX(DataLoadLogKey)
FROM DataLoadLog
WHERE BusinessUnitKey = ` + businessUnitKey + `;`
statement = snowflake.createStatement({sqlText: sql});
result_set = statement.execute();
while (result_set.next()) {
dataLoadLogKey = result_set.getColumnValue(1);
}
var TableName = 'ProductType'
,StoredProcName = 'SAMPLE_PROC()'
,StarDateTime = LoadDate
,EndDateTime = NULL
,Status = 'In Progress'
,LoadDescription = 'Loading Data' ;
sql = `CALL dbo.usp_procedure(:1,:2,:3,:4,:5,:6,:7); `
statement = snowflake.createStatement({
sqlText: sql,
binds: [dataLoadLogKey,TableName,StoredProcName,StarDateTime,EndDateTime,Status,LoadDescription]
});
message= "SUCCESSFUL";
return message;
$$;
call SAMPLE_PROC();
Snowflake stored procedures are written in JavaScript, which can execute SQL statements by calling a JavaScript API. This API is similar to, but not identical to, the APIs in Snowflake connectors and drivers (Node.js, JDBC, Python, etc.).
Details: https://docs.snowflake.com/en/sql-reference/stored-procedures-usage.html#implementation-and-api
You would be able to find a couple of code examples:
https://docs.snowflake.com/en/sql-reference/stored-procedures-usage.html#examples
Related
I am using Snowflake stored procedures to try and log errors as they occur. The current stored proc has an if/else statement, but I'm just trying to get one section working for now since the code is the more or less the same with variations to the SQL statements.
create or replace Procedure PLog(
PName varchar,
CName varchar,
PType varchar)
returns varchar
not null
language javascript
AS
$$
var cyc_id_sql = `SELECT case when count(CycleId) > 0 then max(CycleID) + 1 else 1 end as CycleId from SCHEMA.TABLE1 where CycleName='${CName}'`;
var cycle_id_create = snowflake.createStatement({ sqlText: cyc_id_sql});
var cycleid = cycle_id_create.execute();
var p_id_sql = `Select case when count(ProcessId) > 0 then max(ProcessID) + 1 else 1 end as ProcessId from SCHEMA.TABLE2 where ProcessName='${PName}'`;
var p_id_create = snowflake.createStatement({ sqlText: p_id_sql});
var processid = p_id_create.execute();
var insertValuesText = `INSERT INTO SCHEMA.TABLE
(
ProcessLogId
,CycleId
,ProcessId
,CycleName
,ProcessName
,ProcessType
,ProcessStatus
,StartTime)
VALUES
(default,${cycleid},${processid},'${value3}','${value4}','${value5}','Started',current_timestamp )`;
var insertValues = snowflake.createStatement({ sqlText: insertValuesText});
insertValues.execute();
$$
When I call this I get the error:
SQL compilation error: syntax error line 12 at position 28 unexpected 'Object'. syntax error line 12 at position 44 unexpected 'Object'. At Statement.execute, line 22 position 13
I think the issue is that the cycle and process statements create a Javascript object instead of the desired value. The desired value being the unique ID. When I run the SQL separately with an empty database I get 1, which is expected so I know the SELECT statements work. When I run and then call:
create or replace Procedure PLog(
PName varchar,
CName varchar,
PType varchar)
returns varchar
not null
language javascript
AS
$$
var cyc_id_sql = `SELECT case when count(CycleId) > 0 then max(CycleID) + 1 else 1 end as CycleId from SCHEMA.TABLE1 where CycleName='${CName}'`;
var cycle_id_create = snowflake.createStatement({ sqlText: cyc_id_sql});
var cycleid = cycle_id_create.execute();
return cycleid
$$
I get [object Object]. I'm not that familiar with JavaScript so any help would be appreciated. I think the issue is that my variables generate instances of an object instead of a usable value for the SQL statement, I just don't know how to fix the issue. Thank you!
when you execute a statement var processid = p_id_create.execute(); processid is the result set, not the actual value you want. you need to fetch it
so here is some example from the doc's
CREATE OR REPLACE PROCEDURE right_bind(TIMESTAMP_VALUE VARCHAR)
RETURNS BOOLEAN
LANGUAGE JAVASCRIPT
AS
$$
var cmd = "SELECT CURRENT_DATE() > TO_TIMESTAMP(:1, 'YYYY-MM-DD HH24:MI:SS')";
var stmt = snowflake.createStatement(
{
sqlText: cmd,
binds: [TIMESTAMP_VALUE]
}
);
var result1 = stmt.execute();
result1.next();
return result1.getColumnValue(1);
$$
;
so your small example should be:
create or replace Procedure PLog(
PName varchar,
CName varchar,
PType varchar)
returns varchar
not null
language javascript
AS
$$
var cyc_id_sql = `SELECT case when count(CycleId) > 0 then max(CycleID) + 1 else 1 end as CycleId from SCHEMA.TABLE1 where CycleName='${CName}'`;
var cycle_id_create = snowflake.createStatement({ sqlText: cyc_id_sql});
var result1 = cycle_id_create.execute();
result1.next();
var cycleid result1.getColumnValue(1);
return cycleid
$$
You are correct that it's returning a JavaScript object. As Simeon notes, this is returning a resultSet. If you're expecting a query to return a scalar (single row with a single column) you can use inline code to get it. However, it will not be modular and harder to read than modular code. This is a great example of where a helper function helps.
For example:
create or replace procedure TEST()
returns string
language javascript
as
$$
var my_scalar = getScalar("select C_NAME from SNOWFLAKE_SAMPLE_DATA.TPCH_SF1.CUSTOMER limit 1");
return my_scalar;
function getScalar(sql){
cmd = {sqlText: sql};
stmt = snowflake.createStatement(cmd);
var rs;
rs = stmt.execute();
rs.next();
return rs.getColumnValue(1);
}
$$;
You can then use the getScalar helper function to collect scalar values you need. If you're only doing it once it won't matter too much. If you're collecting a few or dozens, then it will keep the code modular, compact, and more readable.
I am fairly new to snowflake working on a stored procedure having date as a parameter, the same parameter will be used in SELECT statement to work as additional column in result set.
Below is the code:
CREATE OR REPLACE PROCEDURE test1 (TEST_DATE VARCHAR)
RETURNS VARCHAR NOT NULL
LANGUAGE javascript
EXECUTE AS CALLER
AS
$$
var prod = TEST_DATE;
var sql_stmt = `select
ID
,Value
,getvariable('PROD') as TestDate
, to_varchar(CURRENT_TIMESTAMP()) CreateDate
from
Table;`;
var statement = snowflake.createStatement( {sqlText:sql_stmt} );
var rs = statement.execute();
rs.next(1);
//return rs.getColumnValue(1);
return rs.getColumnValue(3);
$$;
Calling above procedure as
CALL test1('2022-02-22');
Returning error as "NULL result in a non-nullable column".
Please suggest how can I use the argument as column name in select.
Thank You.
Binding Variables:
Binding a variable to a SQL statement allows you to use the value of the variable in the statement.
CREATE OR REPLACE PROCEDURE test1 (TEST_DATE VARCHAR)
RETURNS VARCHAR NOT NULL
LANGUAGE javascript
EXECUTE AS CALLER
AS
$$
var sql_stmt = `select
ID
,Value
, :1 as TestDate
, to_varchar(CURRENT_TIMESTAMP()) AS CreateDate
from Table;`;
var statement = snowflake.createStatement( {sqlText:sql_stmt, binds: [TEST_DATE]} );
var rs = statement.execute();
...
$$;
I think Binding like mentioned above is the more proper method, but you could also use string formatting its a bit more readable.
CREATE OR REPLACE PROCEDURE test1 (TEST_DATE VARCHAR)
RETURNS VARCHAR NOT NULL
LANGUAGE javascript
EXECUTE AS CALLER
AS
$$
var prod = TEST_DATE;
var sql_stmt = `select
ID
,Value
,'${TEST_DATE}' as TestDate
, to_varchar(CURRENT_TIMESTAMP()) CreateDate
from
Table;`;
var statement = snowflake.createStatement( {sqlText:sql_stmt} );
var rs = statement.execute();
rs.next(1);
//return rs.getColumnValue(1);
return rs.getColumnValue(3);
$$;
I have created stored procedure using below code I am getting error.
CREATE OR REPLACE PROCEDURE testproc()
returns string not null
language javascript
as
$$
var sql_textA = "ALTER SESSION SET TIMEZONE = 'UTC'" ;
var stmt = snowflake.createStatement({ sqlText: sql_textA});
var rs = stmt.execute();
var sql_textb="SELECT CURRENT_TIMESTAMP;"
var stmt = snowflake.createStatement({ sqlText: sql_textA});
var rs = stmt.execute();
return "succes";
$$
;
call testproc()
getting error like below
"Stored procedure execution error: Unsupported statement type 'ALTER_SESSION'. At Statement.execute, line 4 position"
You need to create the procedure with CALLER rights:
CREATE OR REPLACE PROCEDURE testproc()
returns string not null
language javascript
execute as caller
as
$$
var sql_textA = "ALTER SESSION SET TIMEZONE = 'UTC'" ;
var stmt = snowflake.createStatement({ sqlText: sql_textA});
var rs = stmt.execute();
var sql_textb="SELECT CURRENT_TIMESTAMP;"
var stmt = snowflake.createStatement({ sqlText: sql_textb});
var rs = stmt.execute();
rs.next();
return rs.getColumnValue(1);
$$
;
call testproc();
https://docs.snowflake.com/en/sql-reference/stored-procedures-rights.html#choosing-between-owner-s-rights-and-caller-s-rights
I would like to create a Snowflake stored procedure with multiple SQL statements, and input multiple parameters which happen to be a list. Having trouble. Is it possible?
My attempt:
CREATE OR REPLACE PROCEDURE SP_MULTI_STATEMENT(NAME string , AGE string)
returns string not null
language javascript
as
$$
var cmd = `
update TABLE_1 set SOMETHING1 = 'OK' where NAME in (${NAME});
update TABLE_2 set SOMETHING2 = 'GREAT' where AGE in (${AGE});
`
var sql = snowflake.createStatement({sqlText: cmd});
var result = sql.execute();
return 'DONE';
$$;
When I call my SP I would like it to be:
call SP_MULTI_STATEMENT('Andy, Brian, Christa','21,23,24');
Most of it looks good, but you need to add more quoted escapes to the list of names.
This example works:
CREATE OR REPLACE PROCEDURE SP_MULTI_STATEMENT(NAMES string , AGES string)
returns string not null
language javascript
as
$$
var cmd = `
select *
from (select 'a' name, 33 age)
where NAME in (${NAMES})
and AGE in (${AGES});
`
var sql = snowflake.createStatement({sqlText: cmd});
var result = sql.execute();
if(result.next()) {
return result.NAME;
}
return 'no results'
$$;
call SP_MULTI_STATEMENT('\'a\', \'b\', \'c\'', '30, 31, 32, 33');
I have recently started to use snowflake and have been stuck at this issue:
I want to clone a table called AB_USER to AB_USER_(current_date). I have written following code to accomplish this:
CREATE or replace PROCEDURE backup_proc()
RETURNS VARCHAR
LANGUAGE javascript
AS
$$
var tab_name = `AB_USER_BCK_2020_`+ current_date();
stat = `create or replace table staging.` + tab_name + ` clone staging.AB_USER`;
var rs = snowflake.execute( { sqlText: stat} );
return 'Done.';
$$;
The problem is I cannot find appropriate function to get current date. Snowflake provides a JS environment but I don't know which function to use to get current date.
I am very new to snowflake so any help in this will be much appreciated.
Thanks.
CURRENT_DATE is an SQL command, so you need to call it as SQL statement with snowflake.execute.
As I see, you want to get values of month and day from current date, so you can use the following procedure:
CREATE or replace PROCEDURE backup_proc()
RETURNS VARCHAR
LANGUAGE javascript
AS
$$
var curdate = snowflake.execute( { sqlText: "SELECT TO_CHAR(CURRENT_DATE,'MMDD') as curdate"} );
curdate.next();
var tab_name = "AB_USER_BCK_2020_"+ curdate.getColumnValue('CURDATE');
var stat = "create or replace table staging." + tab_name + " clone staging.AB_USER";
var rs = snowflake.execute( { sqlText: stat} );
return "Done.";
$$
;