Use of variable in result_scan() snowflake stored procedure - variables

I am trying to store the result of a last_query_id() as a variable and then later on in the stored procedure I am trying to use it in a table(result_scan()). I am coming across a number of errors when doing this, however I'm sure it's my level of knowledge of how snowflake works that s the problem. My code currently looks like this:
Declare query_id as varchar;
...
a number of queries;
...
query_id := (select last_query_id());
...
Some more queries
...
let c1 CURSOR for select * from table(result_scan(:query_id));
This is giving me an error saying result_scan() requires a string. I have tried using CAST to convert it to a string however this is not working either.
Thanks!

The assignment is possible:
BEGIN
LET query_id varchar;
SELECT 1 AS c;
query_id := (select last_query_id());
RETURN :query_id;
END;
The RESULT_SCAN function requires string literal so the following will not work:
DECLARE
query_id varchar;
r INT;
BEGIN
SELECT 1 AS c;
query_id := (select last_query_id());
LET c1 CURSOR for select * from table(result_scan(?));
OPEN C1 USING(:query_id);
FETCH c1 INTO r;
RETURN r;
END;
A workaround could be usage of EXECUTE IMMEDIATE and RESULTSET:
DECLARE
rs RESULTSET;
query_id VARCHAR;
BEGIN
SELECT 1 AS col1, 'a' AS col2;
query_id := (SELECT last_query_id());
let sql VARCHAR := 'select * from table(result_scan(''' || query_id || '''))';
rs := (EXECUTE IMMEDIATE :sql);
RETURN TABLE(rs);
END;
Output:

the syntax for assigning the result of a SELECT to a variable is
SELECT COL1 ... INTO variable
It's documented here

Related

run a query saved in a row value

The following select statement gives me three cols and one row.
QueryA
SELECT
-- some calculations and manipulations
x, y, queryB
.....
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE TABLE_SCHEMA = UPPER($sch_name)
AND TABLE_NAME = UPPER($tab_name);
One of the returned columns has a query stored. Output
x, y, queryB
aa bb select * from stg.new
How can I extend the QueryA such that I select and run the query B and the final output returned is that of queryB not queryA?
Here is a sample of reading from one table to get the SQL, executing the SQL on a different table, and then returning the result of that second statement:
create or replace transient table T1 as
select 'This is the final result.' as THE_RESULT
;
create or replace transient table SQL_TO_RUN as
select 'select * from T1' SQL_STATEMENT
;
create or replace procedure myprocedure()
returns table()
language sql
execute as caller
as
$$
declare
rs resultset default (select SQL_STATEMENT from SQL_TO_RUN);
c cursor for rs;
sqlStatement string;
rsFinal resultset;
begin
for rowContents in c do
sqlStatement := rowContents.SQL_STATEMENT;
end for;
rsFinal := (execute immediate :sqlStatement);
return table(rsFinal);
end;
$$
;
call myprocedure();

Trying to query a redshift within SELECT statement

Current table1:
col1
-------------
schema.table1
schema.table2
schema.table3
Desired table1:
col1 col2
------------------------------------------------------------
schema.table1 value of (select count(*) from schema.table1)
schema.table2 value of (select count(*) from schema.table1)
schema.table3 value of (select count(*) from schema.table1)
It is not working, I tried using function too, but function doesn't allow to use 'FROM'
select col1, (select count(*) from col1)
from table1
I am trying to create this query in redshift. Can anyone please help me out?
To perform this task you will need a stored procedure AND a defined cursor. The stored procedure allows for looping and the cursor provides the ability to execute a newly created statement (dynamic querying).
For example:
Create the starting materials, 3 tables and a table that references these tables.
create table foo as (select 1 as A);
create table goo as (select 2 as A);
create table hoo as (select 3 as A);
create table tabs as (select 'foo' as tab union all select 'goo' union all select 'hoo');
Next define the stored procedure the will create the dynamic SQL
CREATE OR REPLACE procedure count_tabs(curs1 INOUT refcursor)
AS
$$
DECLARE
row record;
statement varchar := '';
union_needed BOOL := false;
BEGIN
for row in select tab from tabs LOOP
IF union_needed THEN
statement := statement || ' UNION ALL ';
END IF;
statement := statement || 'select \'' || row.tab || '\' as table_name, count(*) as table_count from ' || row.tab ;
union_needed := true;
END LOOP;
RAISE NOTICE 'sql to execute: %',statement;
open curs1 for execute statement;
END;
$$ LANGUAGE plpgsql;
Lastly we need to call the procedure and execute the cursor
call count_tabs('mycursor');
fetch 1000 from mycursor;
A few notes on this:
This assumes you want the results as output on your bench. If you want to create a table with the results this is doable in the same structure
Since the FROM clause value(s) is unknown at compile time this needs to be done in 2 steps - create the query and then execute the query.
I believe you can have the procedure walk this same cursor itself but doing this is exceptionally slow

How include array (or similar) into an in-clause SQL statement?

I am new to oracle and PL SQL. Currently I struggle with the handling of arrays and "similar things" like i.e. collection. I am trying to build a procedure like:
procedure insert_by_array( my_array some_array_type)
begin
insert into table1 (some_column)
select some_column
from table2
where column2 in my_array
;
end;
However I could not make I did try some array types but I did not find the right one. The entries of the type must be varchar2 - a part of this criterium I am open to any array type. I.e when my array_type is
type array_of_strings is varray(100) of varchar2(40);
My error would be: "local collection types are not alowed in sql statements"
I am using Oracle Database 12c Enterprise Edition Release 12.1.0.2.0.
So at the end, this worked:
create type table_of_strings IS TABLE OF VARCHAR2(64); --define it global;
declare
my_table table_of_strings;
begin
my_table := table_of_strings('aaa', 'bb','c');
insert into table1 (some_column)
select some_column
from table2
where column2 in (select * from table(my_table))
;
end;
First of all, you have to define sql level collection. (varray is not an option)
create type array_of_strings as table of varchar2(40);
Now you can use table or "member of" approach
declare
c array_of_strings := new array_of_strings();
begin
c.extend();
c(c.count) := 'A';
c.extend();
c(c.count) := 'B';
for rec in (select * from dual where 'A' member of c ) loop
dbms_output.put_line('Option with memeber of ');
end loop;
for rec in (select * from dual where 'A' in (select * from table(c))) loop
dbms_output.put_line('Option with table');
end loop;
end;
As error says, local collections, defined in procedure, function, code block, cannot be used in queries, at least in Oracle 11 which I use.
This does not work (PLS-00642):
declare
type strings is table of varchar2(5);
v_i strings := strings('A', 'X', 'Q');
v_o strings;
begin
select * bulk collect into v_o from dual where dummy in (select * from table(v_i));
end;
So... either use type defined at schema level (your own or predefined sys.odcivarchar2list):
declare
type strings is table of varchar2(5);
v_i strings := strings('A', 'X', 'Q');
v_o strings;
v_so sys.odcivarchar2list := sys.odcivarchar2list();
begin
v_so.extend(v_i.count);
for i in 1..v_i.count loop
v_so(i) := v_i(i);
end loop;
select * bulk collect into v_o from dual where dummy in (select * from table(v_so));
end;
... either use dynamic sql:
declare
type strings is table of varchar2(5);
v_i strings := strings('A', 'X', 'Q');
v_o strings;
v_str varchar2(4000);
begin
for i in 1..v_i.count loop
v_str := v_str || case when i > 1 then ', ' end || ''''||v_i(i)||'''';
end loop;
execute immediate 'select * from dual where dummy in ('||v_str||')' bulk collect into v_o ;
end;
... either use loop (probably slowest):
declare
type strings is table of varchar2(5);
v_i strings := strings('A', 'X', 'Q');
v_o strings := strings();
begin
for rec in (select * from dual) loop
if rec.dummy member of v_i then
v_o.extend();
v_o(v_o.count) := rec.dummy;
end if;
end loop;
end;

Dynamic SQL - ORACLE

I have the following procedure, which does not compile correctly, because it refers to non existing objects (table does not exist)
Here is only a section of the code (i used generic names for tables and columns):
DECLARE
C INTEGER := 0;
BEGIN
SELECT COUNT(1) INTO C FROM USER_TABLES WHERE TABLE_NAME = 'MY_TABLE';
IF C > 0 THEN
DECLARE
CURSOR c_maps IS SELECT COLUM_NAME1, COLUM_NAME2 FROM MY_TABLE WHERE ACTIVE = 1;
BEGIN
FOR prec IN c_maps LOOP
some code...;
END LOOP;
EXECUTE IMMEDIATE 'some code..';
END;
END IF;
END;
/
I don't know how to write this statement dynamically, since the table "MY_TABLE" does not exist:
CURSOR c_maps IS SELECT COLUM_NAME1, COLUM_NAME2 FROM MY_TABLE WHERE ACTIVE =1;
I also tried to write it like:
CURSOR c_maps IS SELECT COLUM_NAME1, COLUM_NAME2 FROM (Select 'MY_TABLE' from dual) WHERE ACTIVE = 1;
However, than it refers to the column "ACTIVE" which also does not exist at compile time...It is possible to write the whole procedure inside "execute immediate" - block? I have tried different variants, however without success
You may need to open the cursor in a different way, so that the non existing table is only referred in dynamic SQL; for example:
declare
c integer := 0;
curs sys_refcursor;
v1 number;
v2 number;
begin
select count(1)
into c
from user_tables
where table_name = 'MY_TABLE';
if c > 0
then
open curs for 'select column_name1, column_name2 from my_table where active = 1';
loop
fetch curs into v1, v2;
exit when curs%NOTFOUND;
dbms_output.put_line(v1 || ' - ' || v2);
end loop;
else
dbms_output.put_line('The table does not exist');
end if;
end;
/

Getting an error in sql, when executing code below.How to declare a table type in plsql. Am a beginner . Please suggest

create or replace procedure BAS_NUM_UPD is
cursor cur is
select distinct o.oi_b,mpr.pa_ke_i,ltrim(substr(convert_171_to_711(cp.p_t_num),1,7),'0') bs_nbr
from t_obj o, mat_pa_rel mp, cor_pa cp
where o.ob_t = 'something'
and o.oi_b = mp.oi_b
and mp.pa_ke_i = cp.pa_ke_i;
l_ba_num_at_i number(10) := get_attribute_id('Ba timber');
flag1 VARCHAR2(10);
type t1 is table of varchar2(10);
par_k t1;
BEGIN
for x in cur loop
BEGIN
select pa_ke_i into par_k from mat_pa_rel where oi_b=x.oi_b ;
if par_k.count=null then
insert into cs_val (oi_b, at_i, value, flag, ) values (x.oi_b, l_ba_num_at_i, null, 1);
end if;
select flag into flag1 from cs_val where at_i = l_ba_num_at_i and oi_b = x.oi_b
and value = x.bs_nbr;
EXCEPTION
when NO_DATA_FOUND THEN
insert into cs_val (oi_b, at_i, value, flag, )
values (x.oi_b, l_ba_num_at_i, x.bs_nbr, 1);
flag1 :='Nothing';
when OTHERS
then
raise_application_error(-20011,'Unknown Exception in PROCEDURE');
END;
end loop;
end BAS_NUM_UPD;
error:
PLS-00642: local collection types not allowed in SQL statements
You should get it running if you do a bulk collect
select pa_ke_i bulk collect into par_k from mat_pa_rel where oi_b=x.oi_b ;
Then I think the if is not right. I think you need to do
if par_k.count = 0 then
But to be honest you might just make a count
select count(*) into l_cnt from mat_pa_rel where oi_b=x.oi_b;
If l_cnt = 0 then ...
Of course l_cnt has to be defined.
You should create type t1 in the schema and not in the pl/sql block.