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
Related
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;
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:
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;
$$;
Can we return a table in Snowflake using sql as language? What is the correct syntax if possible?
create or replace procedure sp()
returns table ()
language sql
as
$$
declare
accountingMonth :=(select dateadd(month,case when day(current_timestamp())<=10 then -1 else 0 end,dateadd(month,0,date_trunc('month',current_date()))));
endmonth :=(select dateadd(month,1,dateadd(month,case when day(current_timestamp())<=10 then -1 else 0 end,dateadd(month,0,date_trunc('month',current_date())))));
currmonth date default accountingMonth;
begin
create or replace temporary table sa as (
select col1,col2, col3,datecol,....col270
from table2
where datecol = :accountingmonth
);
end;
select * from sa;
$$
Yes, it is possible to return table from strored procedure using RESULTSET
CREATE OR REPLACE PROCEDURE sp()
RETURNS TABLE(col1 INTEGER, ...)
LANGUAGE SQL
AS
BEGIN
-- ...
let RESULTSET DEFAULT (select * from sa);
RETURN TABLE(res);
END;
In the example below the working_one stored procedure works, while the broken_one does not. The only difference between the two is letters case of SQL statement.
create table tmp (
raw_json variant
);
-- 2019-01-01 = 1546347600000
-- 2018-01-01 = 1514811600000
insert into tmp select parse_json('{ "timestamp":1514811600000}');
create or replace procedure working_one(TIME_VALUE varchar)
returns varchar
language javascript
as
$$
var stmtString = "delete from tmp where to_timestamp(raw_json:timestamp::string) < to_timestamp(:1);"
var stmt = snowflake.createStatement({sqlText: stmtString, binds: [TIME_VALUE]})
var rs = stmt.execute()
rs.next()
return rs.getColumnValue(1)
$$;
create or replace procedure broken_one(TIME_VALUE varchar)
returns varchar
language javascript
as
$$
var stmtString = "DELETE FROM TMP WHERE TO_TIMESTAMP(RAW_JSON:TIMESTAMP::STRING) < TO_TIMESTAMP(:1);"
var stmt = snowflake.createStatement({sqlText: stmtString, binds: [TIME_VALUE]})
var rs = stmt.execute()
rs.next()
return rs.getColumnValue(1)
$$;
call broken_one('1546347600000');
call working_one('1546347600000');
I don't believe the problem is in the case-sensitivity of the SQL, or even that it's a Stored Procedure. The issue is that the attribute inside your JSON is case-sensitive. Try this and tell me if that works better for you.
create or replace procedure fixed_one(TIME_VALUE varchar)
returns varchar
language javascript
as
$$
var stmtString = "DELETE FROM TMP WHERE TO_TIMESTAMP(RAW_JSON:timestamp::STRING) < TO_TIMESTAMP(:1);"
var stmt = snowflake.createStatement({sqlText: stmtString, binds: [TIME_VALUE]})
var rs = stmt.execute()
rs.next()
return rs.getColumnValue(1)
$$;