How do I work with variables in snowflake - snowflake-cloud-data-platform

I set this up a while ago in something that is not really used. I was under the impression that it worked at the time, but I'm trying to test it now and am getting some errors.
Here is my snowflake code:
var rs = snowflake.createStatement( { sqlText: "select count(*) from toptal.stage_resellers" } ).execute();
rs.next();
var resellers = rs.getColumnValue(1);
I that that var resellers was going to define a variable that would have the number of rows in stage_resellers, but I'm not confident of that.
I decided to test it just by inserting the value into a logging table that I am using into an unused column for the time being.
Here is that code:
var stmt1 = snowflake.execute ( { sqlText:`insert into toptal.processing_executions values ('merge into dim_resellers', current_timestamp, 'processing', :resellers);`});
I'm getting this error:
Execution error in store procedure PROCESSING: SQL compilation error: error line 1 at position 110 Bind variable :resellers not set. At Snowflake.execute, line 47 position 24
I tried futzing around with setting the variable, to no avail.
I have a feeling that I am mixing up environments here, but I'm not sure what's going on.

To execute:
var stmt1 = snowflake.execute ( { sqlText:`insert into toptal.processing_executions values ('merge into dim_resellers', current_timestamp, 'processing', :resellers);`});
variables has to be provided as ? or :1. Code becomes:
var stmt1 = snowflake.execute({
sqlText: `insert into toptal.processing_executions
values ('merge into dim_resellers', current_timestamp,
'processing', ?)`
,binds: [resellers] } );
More at documentation: Binding Variables

Related

How to bind JavaScript based date column in Snowflake SQL

I am creating snowflake JavaScript based store procedure. How can i refer the date data type variable in snowflake sql.
Here is the sample code:
In the below code ,please suggest how can i use 'dnblatestdt' variable in sql statement.
create or replace procedure test_proc_registration_master_perished_dt(PARAM_REG_SUB_UUID VARCHAR)
returns varchar not null
language javascript
as
$$
/*get latest ingestion_uuid for the given state*/
var step01=`select distinct dnb_applicable_dt,ingestion_uuid from temp_registration_hash_master `;
var statement01=snowflake.createStatement( {sqlText: step01,binds: [PARAM_REG_SUB_UUID]} );
variable1= statement01.execute();
variable1.next();
dnblatestdt=variable1.getColumnValue(1);
ingsuuid=variable1.getColumnValue(2);
/* check if the ingestion is successful or not*/
var step02=`select INGESTION_SUCCESSFUL from FILE_INGESTION_HISTORY where ingestion_uuid=:1 and date=:2::TIMESTAMP_LTZ::DATE`;
var statement02=snowflake.createStatement( {sqlText: step02,binds: [ingsuuid,dnblatestdt]} );
variable2= statement02.execute();
variable2.next();
ingsindc=variable2.getColumnValue(1);
return 'success'
$$
So I wrote a much simpler function that uses a similar pattern to your code:
create or replace procedure test_proc()
returns varchar not null
language javascript
as
$$
var step01 = `SELECT 6::number, '2022-01-27'::timestamp_ntz;`;
var statement01 = snowflake.createStatement( {sqlText: step01} );
results1 = statement01.execute();
results1.next();
ingsuuid = results1.getColumnValue(1);
dnblatestdt = results1.getColumnValue(2);
/* check if the ingestion is successful or not*/
var step02=`SELECT :1 * 2, DATEADD(year,-1, :2::timestamp_ntz);`;
var statement02 = snowflake.createStatement( {sqlText: step02,binds: [ingsuuid , dnblatestdt]} );
results2 = statement02.execute();
results2.next();
ingsindc = results2.getColumnValue(1);
return 'success'
$$
;
and using it works for me:
call test_proc();
TEST_PROC
success
I swapped the order of the reading parameters on the first function, but that should not be a problem.
this makes me thing your casting on the second instance is not working
:2::TIMESTAMP_LTZ::DATE
so I would suggest moving that casting to the first function, which you can test outside the stored procedure, thus.
SELECT DISTINCT dnb_applicable_dt::TIMESTAMP_LTZ::DATE, ingestion_uuid
FROM temp_registration_hash_master
when that is happy, you shouldn't need any casting on the second used of the values.

Stored procedure - get anticipated columns before fully executing statement?

I'm working through a stored procedure and wondering if there's a way to retrieve the anticipated result column list from a sql statement before fully executing.
Scenarios:
dynamic SQL
a UDF that might vary the columns outside of our control
EX:
//inbound parameter
SET QUERY_DEFINITION_ID = 12345;
//Initial statement pulls query text from bank of queries
var sqlText = getQueryFromQueryBank(QUERY_DEFINITION_ID);
//now we run our query
var cmd = {sqlText: sqlText };
stmt = snowflake.createStatement(cmd);
What I'd like to be able to do is say "right - before you run this, give me the anticipated column list" so I can compare it to what's expected.
EX:
Expected: [col1, col2, col3, col4]
Got: [col1]
Result: Oops. Don't run.
Rationale here is that I want to short-circuit the execution if something is missing - before it potentially runs for a while. I can validate all of this after the fact, but it would be really helpful to stop early.
Any ideas very much appreciated!
This sample SP code shows how to get a list of columns that a query will project into the result before you run the query. It should only be used for large, long running queries because it will take a few seconds to get the column list.
There are a couple of caveats. 1) It will only return the names of the columns. It won't tell you how they were built, that is, whether they're aliased, direct from a table, calculated, etc. 2) The example query I used is straight from the Snowflake documentation here https://docs.snowflake.com/en/user-guide/sample-data-tpcds.html#functional-query-definition. For convenience, I minimized the query to a single line. The output of the columns includes object qualifiers in addition to the column names, so V1.I_CATEGORY, V1.D_YEAR, V1.D_MOY, etc. If you don't want them to make it easier to compare names, you can strip off the qualifiers using the JavaScript split function on the dot and take index 1 of the resulting array.
create or replace procedure EXPLAIN_BEFORE_RUNNING()
returns string
language javascript
execute as caller
as
$$
// Set the context for the session to the TPC-H sample data:
executeNonQuery("use schema snowflake_sample_data.tpcds_sf10tcl;");
// Here's a complex query from the Snowflake docs (minimized to one line for convienience):
var sql = `with v1 as( select i_category, i_brand, cc_name, d_year, d_moy, sum(cs_sales_price) sum_sales, avg(sum(cs_sales_price)) over(partition by i_category, i_brand, cc_name, d_year) avg_monthly_sales, rank() over (partition by i_category, i_brand, cc_name order by d_year, d_moy) rn from item, catalog_sales, date_dim, call_center where cs_item_sk = i_item_sk and cs_sold_date_sk = d_date_sk and cc_call_center_sk= cs_call_center_sk and ( d_year = 1999 or ( d_year = 1999-1 and d_moy =12) or ( d_year = 1999+1 and d_moy =1)) group by i_category, i_brand, cc_name , d_year, d_moy), v2 as( select v1.i_category ,v1.d_year, v1.d_moy ,v1.avg_monthly_sales ,v1.sum_sales, v1_lag.sum_sales psum, v1_lead.sum_sales nsum from v1, v1 v1_lag, v1 v1_lead where v1.i_category = v1_lag.i_category and v1.i_category = v1_lead.i_category and v1.i_brand = v1_lag.i_brand and v1.i_brand = v1_lead.i_brand and v1.cc_name = v1_lag.cc_name and v1.cc_name = v1_lead.cc_name and v1.rn = v1_lag.rn + 1 and v1.rn = v1_lead.rn - 1) select * from v2 where d_year = 1999 and avg_monthly_sales > 0 and case when avg_monthly_sales > 0 then abs(sum_sales - avg_monthly_sales) / avg_monthly_sales else null end > 0.1 order by sum_sales - avg_monthly_sales, 3 limit 100;`;
// Before actually running the query, generate an explain plan.
executeNonQuery("explain " + sql);
// Now read the column list from the explain plan from the result set.
var columnList = executeSingleValueQuery("COLUMN_LIST", `select "expressions" as COLUMN_LIST from table(result_scan(last_query_id())) where "operation" = 'Result';`);
// For now, just exit with the column list as the output...
return columnList;
// Your code here...
// Helper functions:
function executeNonQuery(queryString) {
var out = '';
cmd = {sqlText: queryString};
stmt = snowflake.createStatement(cmd);
var rs;
rs = stmt.execute();
}
function executeSingleValueQuery(columnName, queryString) {
var out;
cmd1 = {sqlText: queryString};
stmt = snowflake.createStatement(cmd1);
var rs;
try{
rs = stmt.execute();
rs.next();
return rs.getColumnValue(columnName);
}
catch(err) {
if (err.message.substring(0, 18) == "ResultSet is empty"){
throw "ERROR: No rows returned in query.";
} else {
throw "ERROR: " + err.message.replace(/\n/g, " ");
}
}
return out;
}
$$;
call Explain_Before_Running();

Retrieve the Variable value and insert into another table

I can retrieve the values of before(0) and after counts(4) from the below statements, but when I make use of those variables (load_cnt_before, load_cnt_after) from the code below and refer them to have the values inserted into a table it says it cant find the variables(refer to error below). How can I use those values to INSERT them into table.
Error: Execution error in stored procedure REC_COUNT_CHECK: SQL compilation error: error line 1 at position 114 invalid identifier 'LOAD_CNT_BEFORE' At Statement.execute, line 25 position 90
Code:
CREATE OR REPLACE PROCEDURE REC_COUNT_CHECK()
RETURNS VARCHAR LANGUAGE JAVASCRIPT
AS $$
/***** Get the Record Count before Refresh ****/
var load_cnt=`SELECT Count(*) as record_cnt from "PLNG_ANALYSIS"."LOADDATA"."LOAD_VERIFICATION" WHERE EXTRACTDATE=Current_date()-1 ;`
var load_cnt_check = snowflake.createStatement({sqlText: load_cnt}).execute();
load_cnt_check.next();
load_cnt_before = load_cnt_check.getColumnValue(1);
/***** Execute the SP ****/
var sp_call = "CALL LOAD_VERIFICATION()"; /***Refreshes data in table LOAD_VERIFICATION***/
var result = snowflake.execute({sqlText: sp_call});
result.next();
var return_msg2 = result.getColumnValue(1);
/***** Check the After Refresh Count ****/
var load_cnt_after=`SELECT Count(*) as record_cnt from "PLNG_ANALYSIS"."HFM"."LOAD_VERIFICATION" WHERE EXTRACTDATE=Current_date() ;`
var load_cnt_check_after = snowflake.createStatement({sqlText: load_cnt_after}).execute();
load_cnt_check_after.next();
load_cnt_after= load_cnt_check_after.getColumnValue(1);
/***** INSERT BEFORE AND AFTER COUNTS INTO LOG TABLE ****/
var insert_status_sp1=`INSERT INTO LOAD_STATUS_LOG_KK values (Current_TIMESTAMP(),1,'LOAD_VERIFICATION','Success','',**load_cnt_before,load_cnt_after**,1);`
var exec_sp1_status = snowflake.createStatement({sqlText: insert_status_sp1}).execute();
exec_sp1_status.next();
return 'Success'
$$;
CALL REC_COUNT_CHECK();
JS variables should be passed into SQL query. The mechanism is called Binding Variables
var insert_status_sp1=`INSERT INTO LOAD_STATUS_LOG_KK values (Current_TIMESTAMP(),1,'LOAD_VERIFICATION','Success','',:1,:2,1);`
var exec_sp1_status = snowflake.createStatement(
{sqlText: insert_status_sp1,binds:[load_cnt_before,load_cnt_after]}
).execute();

using variable while inserting data into a table - snowflake procedure

i am inserting a query from a variable into log table , but it is throwing error as below.
Failed: Code: 100183\n State: P0000\n Message: SQL compilation error:
syntax error line 3 at position 33 unexpected 'MM'.
syntax error line 7 at position 58 unexpected 'Current_Timestamp'
please refer INSERT_VOL2 where we are iserting values into a log table by using parameters. where v_WORK_SQL_ALRT_VOL2 is having the query , same query we are trying to insert into a log table. but it is throwing error.
below is the procedure code.
CREATE OR REPLACE PROCEDURE CDW_PROC.SAMPLE_PROCEDURE(col1 FLOAT, COL2 VARCHAR, COL3 VARCHAR, COL4 VARCHAR, COL5 VARCHAR, COL6 VARCHAR)
RETURNS VARCHAR(10000)
LANGUAGE JAVASCRIPT
STRICT
EXECUTE AS OWNER
AS
$$
try
{
var v_FILTER_ID=0;
var v_A_TYPE=COL2
var v_TYPE=COL3
var v_FILTER_ATTRIBUTE
var v_ORG=COL4;
var v_FILTER_CONDITION,v_FILTER_VALUE,v_FILTER_DESC;
var v_BRAND ='v_BRAND';
var v_F_TIME_CUR = 'v_F_TIME_CUR';
var v_F_TIME_PREV='v_F_TIME_PREV';
var v_F_RANK='v_F_RANK';
var v_F_TIME_BUCKET='v_F_TIME_BUCKET';
var v_CODE='v_CODE';
var v_ID=col1;
var v_TIME_FRAME=COL5;
var v_WK_MTH_FLG=COL6;
var SEL_SQL=snowflake.execute({sqlText: "SELECT ID,TYPE,ORG,SUB_TYPE,FILTER_ID,FILTER_DESC,FILTER_ATTRIBUTE,FILTER_CONDITION,FILTER_VALUE,TIME_FRAME,WK_MTH_FLG FROM CDW_DB.FCT_TABLE WHERE ID=? AND TYPE =? AND SUB_TYPE =? AND ORG=? AND TIME_FRAME=? AND WK_MTH_FLG =?",binds:[v_ID,v_A_TYPE, v_TYPE, v_ORG, v_TIME_FRAME, v_WK_MTH_FLG]});
while(SEL_SQL.next())
{
var v_ID=SEL_SQL.getColumnValue(1);
var v_A_TYPE=SEL_SQL.getColumnValue(2);
v_WORK_SQL_ALRT_VOL2 = `insert into CDW_US_DIMS_DB.PLANNED_CALL1
select DISTINCT FCT.PFZ_CUST_ID,
CAST(TO_CHAR(FCT.CALL_DATE_VOD ,'MM/DD/YYYY') AS VARCHAR(10)) AS PLANNED_CALL_DATE,
RANK() OVER (PARTITION BY FCT.PFZ_CUST_ID ORDER BY FCT.DT_SK ASC,FCT.CREATEDDATE ASC) AS RNK
from CDW_US_PROCESSING_VW.VVA_REP_PLANNED_CALLS FCT WHERE PFZ_CUST_ID <> -1
and FCT.${v_F_SALES_ORG_CODE}
and CALL_DATE_VOD > CURRENT_TIMESTAMP(0) QUALIFY RNK=1;`;
var v_WORK_SQL_EXEC=snowflake.createStatement({sqlText: v_WORK_SQL_ALRT_VOL2});
var VOL2_RESULT=v_WORK_SQL_EXEC.execute();
var INSERT_VOL2=snowflake.execute({sqlText: "INSERT INTO CDW_DB.log_tbl VALUES ("+v_ID+",'"+v_A_TYPE+"','"+v_WORK_SQL_ALRT_VOL2+"',Current_Timestamp)"});
var RESULT='Success';
return RESULT;
}
catch(err)
{
RESULT="Failed: Code: "+err.code+"\\n State: "+ err.state;
RESULT+="\\n Message: "+err.message;
RESULT+="\\n Stack Trace:\\n"+err.StackTraceTxt;
return RESULT;
}
$$
;
The pasted code has multiple errors that would prevent it from working, or even giving that specific error message:
A block needs to be closed before catch with a }.
The variable col1 should be COL1.
v_F_SALES_ORG_CODE is never defined, but used.
Once all that is fixed, everything works well until these lines:
var v_WORK_SQL_EXEC=snowflake.createStatement({sqlText: v_WORK_SQL_ALRT_VOL2});
var VOL2_RESULT=v_WORK_SQL_EXEC.execute();
But then we find this:
var INSERT_VOL2=snowflake.execute({sqlText: "INSERT INTO CDW_DB.log_tbl VALUES ("+v_ID+",'"+v_A_TYPE+"','"+v_WORK_SQL_ALRT_VOL2+"',Current_Timestamp)"});
The problem is that v_WORK_SQL_ALRT_VOL2 is a full sql query - and inserting a full SQL query string in the middle of an insert statement will simply not work.
This code needs a lot of cleaning and work, but at least we found where the two errors in the question are coming from.
i am able to insert that values now, after assigning current_timestamp values to a variable and that variable is using in Insert query. Thank you for your suggestions. grately appriciated.

How to assign a sql query result to a variable in stored procedure

I am trying to assign a simple sql query result in stored procedure to a variable which I will use it later in another sql statement. If I execute below statement with out putting in procedure it works but not with stored procedure, I get an error while calling sp , Can someone please help me here ?
Procedure code:
$$
VAR NAME = 'ABC'
SET (COUNT_VALUE) = (SELECT COUNT(*) FROM COUNT_TABLE)
With out Procedure below code works
SET (COUNT_VALUE) = (SELECT COUNT(*) FROM COUNT_TABLE)
select $COUNT_VALUE
Thanks
Here's an example that uses a simple helper function to return a result set from a query. You can read the Snowflake docs to see what the result set API has in it. The getResultSet function returns a variable that has the results of the query. Since the SQL is a count, you need to use rs.next() once to get to the first row and then read the value in the aliased count(*). You could also use rs.getColumnValue(1) to get a column by ordinal position, but I recommend using column names with SQL aliases is necessary.
create or replace procedure COUNT_EXAMPLE()
returns string
language javascript
as
$$
var rowCount = 0;
var sql = "select count(*) as ROW_COUNT from SNOWFLAKE_SAMPLE_DATA.TPCH_SF10000.ORDERS;";
try {
var rs = getResultSet(sql);
if (rs.next()) {
var rowCount = rs.getColumnValue("ROW_COUNT");
} else {
return "Error: Count query failed.";
}
}
catch(err) {
return "Error: " + err.message;
}
return "The table has " + rowCount + " rows.";
//--------------------------- End of main function ---------------------------
function getResultSet(sql){
cmd1 = {sqlText: sql};
stmt = snowflake.createStatement(cmd1);
var rs;
rs = stmt.execute();
return rs;
}
$$;
call COUNT_EXAMPLE();

Resources