Running query dynamically inside snowflake sql stored procedure - snowflake-cloud-data-platform

I need to run the query which is saved in a field in one table and insert the value of query output into another table.
To simplify the ask I have created dummy tables and try to test the logic.
Table 1
create table tsql(id string, q string);
insert into tsql values (1,'Select current_date');
Table tsql has select query in field name q.
Table 2
create table tinput(d date);
Table 2 will get updated from the value in table 1.
Below are the stored procedure I am trying to write. I know this can be done in javascript stored proc but I need to write this in sql as we are following SQL for all other.
Procedure so far.
create or replace procedure sqlreadwrite(id string)
returns string
language sql
as
$$
Declare
select_statement String;
begin
create or replace temp table tk
as select q from tsql where id = :id;
--select_statement := 'insert into tinp values (execute immediate 'Select Q from tk')';
execute immediate 'insert into tinp values (execute immediate 'Select Q from tk')';
return 'Success';
end;
$$;
Till now it is failing.

you don't need to call execute immediate twice, you should call it only once. One thing i wee is you have not specified the list of columns in you INSERT statement , it is always better to specify the list of column.
-- untested
execute immediate 'insert into tinp values (Select Q from tk)';

I figured out a way, however I am open to suggestion and better approach.
Below is the query.
create or replace procedure sqlread(id string)
returns string
language sql
as
$$
Declare
select_statement String;
res resultset;
value string;
res1 resultset;
v string;
begin
create or replace temp table tk as select q from tsql where id = :id;
select_statement := 'Select Q from tk';
res := (execute immediate :select_statement);
let c1 cursor for res;
for row_variable in c1 do
value := row_variable.Q;
res1 := (execute immediate :value);
let c1 cursor for res1;
for row_variable1 in c1 do
v := row_variable1.current_date::date;
insert into tinp values (:v);
end for;
End For;
return v;
end;
$$;

If the target table (tinput) will only accept dates, I wonder what kind of queries are stored in the source table (tsql)? Anyway, I assume there is a business requirement behind this, so your approach should be OK.
Some improvements:
You may remove the TEMP table as it doesn't provide any benefits.
If your procedure will only run 1 query from tinput (if IDs are unique), then you don't need a loop.
Here is the sample code:
create or replace procedure sqlread(p_id string)
returns string
language sql
as
$$
Declare
select_statement String;
res resultset;
value string;
res1 resultset;
v string;
begin
select_statement := 'select q from tsql where id = ?';
res := (execute immediate :select_statement using (P_ID));
let c1 cursor for res;
open c1;
fetch c1 into value;
res1 := (execute immediate :value);
let c2 cursor for res1;
open c2;
fetch c2 into value;
insert into tinput values (:value);
return :value;
exception
when other then
return 'error';
end;
$$;

Related

how to call variable result into another select statment in sql stored procedure

Hi I have one doubt in snowflake
how to use variable result in the next sselect session.
I want stored one statement result in variable and that variable result need to call another statment in snowflake server .
use schema test.public;
create or replace procedure empresult()
returns table ()
language sql
as
$$
set empresult=(select deptid from TEST.PUBLIC.DEPT where deptid=10)
declare res resultset(
select * from emp where deptno in ($empresult)
)
begin
return table(res);
end;
$$;
above statment getting error.
Syntax error: unexpected 'declare'. (line 4)
please tell me how to write stored procedure query to call the one statment result into another session select statment task.
The sample code is missing colons and the correct syntax for variables.
One possible fix that works:
create or replace procedure empresult()
returns table ()
language sql
as
$$
declare
empresult integer;
begin
select deptid into :empresult from DEPT where deptid=10;
let res resultset := (select * from emp where deptno = :empresult);
return table(res);
end;
$$;
call empresult();
Staging data:
create temp table dept as select 10 deptid;
create temp table emp as select 'a' a, 'b' b, 10 deptno;

how to run simple select query and get reusult in snowflakes procedure?

how to run simple select query and get reusult in snowflakes procedure?
CREATE OR REPLACE PROCEDURE COARSDB0P_DB.COUNT_MISMATCH()
RETURNS VARCHAR
LANGUAGE JAVASCRIPT
AS
$$
var command ="SELECT b.TABLE_CATALOG,b.TABLE_SCHEMA,b.TABLE_NAME,b.TABLE_TYPE,b.ROW_COUNT as Dev_COUNT,a.ROW_COUNT as UAT_COUNT FROM TABLE A ,information_schema.tables B where b.TABLE_NAME=a.TABLE_NAMES and b.TABLE_SCHEMA=a.TABLE_SCHEMA and b.TABLE_TYPE=a.TABLE_TYPE and TRY_CAST(b.ROW_COUNT as NUMBER) != TRY_CAST(a.ROW_COUNT as NUMBER);"
var cmd1_dict = {sqlText: command};
var stmt = snowflake.createStatement(cmd1_dict);
var rs = stmt.execute();
rs.next();
var output = rs.getColumnValue();
return output;
$$;
I need to return the actualy output of mentioned SLECT query.
See Returning tabular data from a stored procedure. Note this is for a SQL stored procedure, not Javascript. You will want something like:
create procedure ...
returns table (catalog varchar, schema varchar, ...)
declare
query varchar;
res resultset;
begin
-- build the dynamic SQL query
query := 'select ...'
res := (execute immediate :query);
return table (res);
end;
You can use Tabular SQL UDFs to return the result:
https://docs.snowflake.com/en/developer-guide/udf/sql/udf-sql-tabular-functions.html#calling-a-sql-udtf

Snowflake Stored Procedure Error for JSON input

I am trying to parse JSON value and getting Syntax Error in stored procedure.
This SELECT statement works fine:
SELECT
parse_json ('{"fName":"Pink","lName":"Panther"}') AS json_data,
json_data:fName::string AS first_name,
json_data:lName::string AS last_name;
While trying same thing in stored procedure, I am getting a syntax error:
CREATE OR REPLACE PROCEDURE extract_json(input_json varchar)
RETURNS TABLE (res varchar)
LANGUAGE SQL
AS
$$
DECLARE
qry string;
res resultset;
BEGIN
qry := 'SELECT parse_json('||:input_json||') AS json_data::sting, json_data:fName::string';
res := (execute immediate qry);
return table(res);
END;
$$
;
CALL extract_json('{"fName":"Pink","lName":"Panther"}');
Expected out, 2 columns only:
FIRST_NAME LAST_NAME
Pink Panther
Any help is appreciated.
Thanks
The are few issues with the code:
a) resulset contains two column so (res varchar) will not work
b) alias json_data::sting cannot be casted
c) missing ' around input_json, ideally it should be bind parameter
CREATE OR REPLACE PROCEDURE extract_json(input_json varchar)
RETURNS TABLE (col VARIANT, res varchar)
LANGUAGE SQL
AS
$$
DECLARE
qry string;
res resultset;
BEGIN
qry := 'SELECT parse_json('''||:input_json||''') AS json_data, json_data:fName::string';
res := (execute immediate qry);
return table(res);
END;
$$
;
CALL extract_json('{"fName":"Pink","lName":"Panther"}');
Output:
Expected out, 2 columns only:
CREATE OR REPLACE PROCEDURE extract_json(input_json varchar)
RETURNS TABLE (firstName VARCHAR, lastName varchar)
LANGUAGE SQL
AS
$$
DECLARE
qry string;
res resultset;
BEGIN
qry := 'SELECT json_data:fName::string, json_data:lName::string FROM (SELECT parse_json('''||:input_json||''') AS json_data)';
res := (execute immediate qry);
return table(res);
END;
$$;
CALL extract_json('{"fName":"Pink","lName":"Panther"}');
Output:

Call a Snowflake procedure from a Procedure

I have a Snowflake SQL procedure, which calls a stored procedure, the calling procedure "PROC_TABLE_COUNT" goes in a for loop dose some processing and calls another procedure "getRowCount" which captures the row count in a specific schema / table.
How to call the procedure and capture the value returned by the procedure.
A sample code for both the procedures is as follows.
CREATE OR REPLACE PROCEDURE PROC_TABLE_COUNT()
returns varchar(20000)
language sql
execute as caller
as
$$
declare
v_err_stmt varchar2;
v_sqlerrm varchar2;
v_src_schema varchar2;
v_tgt_schema varchar2;
v_sis_table varchar2;
v_census_table varchar2;
v_select_stmt varchar2;
v_insert_stmt varchar2;
--RCN count
v_sis_count integer;
v_census_count integer;
v_select_RCN_stmt varchar2;
begin
v_src_schema := 'SCHEMA_1';
v_sis_count := getRowCount('SCHEMA_1','TABLE_1');
v_err_stmt := v_select_RCN_stmt;
-- The row count will be captured and inserted into a table.
end;
$$;
create or replace procedure getRowCount(schema_name varchar, table_name varchar)
returns table(a integer)
language sql
as
$$
declare
res RESULTSET;
query varchar default 'SELECT count(*) FROM ' || :schema_name || '.' || :table_name ;
begin
res := (execute immediate :query);
return table (res);
end;
$$;
In place of below in procedure code - PROC_TABLE_COUNT() -
v_sis_count := getRowCount('SCHEMA_1','TABLE_1');
v_err_stmt := v_select_RCN_stmt;
Use following -
call getRowCount('PUBLIC','TABLE_1');
v_err_stmt := (select * from table(result_scan(last_query_id())) );
insert into TABLE_1 values (:v_err_stmt); - or whatever table name

building a select statement in oracle using values stored in variables

Is there a way to build a select statement in oracle using values stored in variables?
For example can you do this:
declare
tbl_var varchar2(10) := "map_set";
begin
select count(*) from tbl_var;
end;
Yes there is, using execute immediate:
declare
tbl_var varchar2(10) := 'map_set';
result number;
begin
execute immediate 'select count(*) from '||tbl_var into result; --save result into variable
dbms_output.put_line('Total rows:'||result); --print result
end;
Second way, you can create a function that receives table name as parameter and return the count:
create function get_count(tbl_var varchar2) return number is
result number;
begin
execute immediate 'select count(*) from '||tbl_var into result;
return result;
end;
After create the function you can query it like this:
select get_count('map_set') from dual;

Resources