Using IF statement with Variable value as Condition in SNowflake - snowflake-cloud-data-platform

I am new to snowflake and SQL scripting. I am trying to achieve a logic to execute commands in IF statement block when a variable condition is true using Snowflake, i went to the documentation but eventually i am doing mistakes in writing code. Can you please help me in correcting it.
//Step 1:
//Declare variable
declare
CNT NUMBER;
//Step 2:
//Assigning Value to variable
begin
CNT := (Select count(*) from CLOUDMED_AI.DATAWAREHOUSE_INTEGRATION_ADMIN.SYNAPSE_TO_SNOWFLAKE_CONTROL );
//Step 3:
//Using Variable in IF statement
IF (CNT < 100)
then
Select top 10 * from CLOUDMED_AI.DATAWAREHOUSE_INTEGRATION_ADMIN.SYNAPSE_TO_SNOWFLAKE_CONTROL
end IF;
end;
But the above lines for me is throwing issues.

Here is an example that works. Different table names, but you should be able to follow the structure.
execute immediate $$
declare
RECORD_COUNT NUMBER;
output RESULTSET;
begin
SELECT COUNT(*) INTO :RECORD_COUNT FROM INFORMATION_SCHEMA.TABLES;
IF (RECORD_COUNT<100) THEN
output:=(SELECT TOP 10 * FROM INFORMATION_SCHEMA.TABLES);
END IF;
RETURN TABLE(output);
end;
$$
;

Related

My function with array as parameter does not work

I proceed to specify my question and the solution I gave to the problem, for the benefit of the community.
I was trying to perform a multi-column insert using the identifier with a function.
For which, I was getting an error, my code was the following:
CREATE OR REPLACE FUNCTION acc.asignar_periodo(ids NUMERIC[], periodo INTEGER,codigo_subdiario VARCHAR)
RETURNS void
VOLATILE
AS
$$
DECLARE
cant_registros integer:= 0;
BEGIN
cant_registros := array_length(ids,1);
FOR i IN 1..cant_registros LOOP
EXECUTE'UPDATE '||$3||' SET periodo_tributario = $2 WHERE id = ids[i]';
END LOOP;
END;
$$ LANGUAGE plpgsql;
and my query is:
SELECT acc.asignar_periodo('{2291,2292,2293,2294,2295,2296,2297,2298,2299,2300,2301,2302}'::NUMERIC[],201612,'_08');
My solution was the following:
CREATE OR REPLACE FUNCTION acc.asignar_periodo(INTEGER[],INTEGER,INTEGER) RETURNS text VOLATILE AS
$$
DECLARE
qty integer:= array_length($1,1);
respuesta varchar := null;
BEGIN
FOR i IN 1..qty LOOP
EXECUTE'UPDATE _'||$3||' SET periodo_tributario = '||$2||' WHERE id = '||$1[i];
END LOOP;
respuesta := 'Periodo '||$2||' asignado a '||qty||' comprobantes del subdiario '||$3;
RETURN respuesta;
END;
$$ LANGUAGE plpgsql;
Note the correction, since when using EXECUTE it is necessary that the arguments escape the statements
There is no to loop needed to process the array. Postgres will process the entry array at once. After all set processing is what SQL is all about. Get into the mindset that whenever you write loop, likely incorrect and much slower. (Yes there occasions where it is necessary, but very few.) So: (see demo)
create or replace function asignar_periodo(ids numeric[], periodo integer,codigo_subdiario varchar)
returns void
language plpgsql
as $$
declare
stmt constant text = 'update %I set periodo_tributario = %s where id = any (''%s'')';
torun text;
begin
--torun = format(stmt, $3, $2, $1); -- this would work but
torun = format(stmt, codigo_subdiario, periodo, ids); -- I perfer parameter names to position reference
raise notice '%', torun;
execute torun;
end ;
$$;

Looping through a cursor with a condition on an updated field [PLSQL]

I am currently implementing a PL/SQL procedure, which balances a value in two lists.
Consider this example as background:
Rec_1 | 2
Rec_2 | 1
Rec_3 | 2
Rec_A | -1
Rec_B | -3
Rec_C | -2
I want to loop through all these values one-by-one and settle as much as possible, i.e. that after the first settlement Rec_1 should be 1, Rec_A should be 0. Afterwards, Rec_1 will be settled with Rec_B such that it gets 1, Rec_B gets -2, and so on.
I want to use two cursors to do this, and update the values in its own procedure (or function, if that is necessary), since there is a little more to do than just update this value.
Now, here is my challenge:
How do I know which cursor to fetch after a settlement has happened?
Right now, my code for this function looks like this:
PROCEDURE SettleLists (
ListNegV SYS_REFCURSOR,
ListPosV SYS_REFCURSOR
) IS
currentNegV TABLENAME%ROWTYPE;
currentPosV TABLENAME%ROWTYPE;
BEGIN
FETCH ListNegV INTO currentNegV;
FETCH ListPosV INTO currentPosV;
LOOP
EXIT WHEN ListNegV%NOTFOUND;
EXIT WHEN ListPosV%NOTFOUND;
IF (currentNegV.NUMERICVALUE < 0)
THEN
IF (currentPosV.NUMERICVALUE > 0)
THEN
Settle(currentPosV, currentNegV);
ELSE
FETCH ListPosV INTO currentPosV;
END IF;
ELSE
FETCH ListNegV INTO currentNegV;
END IF;
END LOOP;
END;
Inside the settle procedure, there will be an UPDATE on both records. Since the variables and cursor values are not updated, this will produce an infinite loop. I could update the parameter of settle when the record is updated in the database as well, but since I am not used to cursors, you might have a better idea.
I could consider the cursor to be strongly typed, if that makes any difference. If there is a better way than using a cursor, feel free to suggest it.
Finally, I was playing around with SELECT FOR UPDATE and UPDATE WHERE CURRENT OF, but it did not seem to work when passing the cursor to a procedure in between. If anyone has some idea on this, I would also appreciate your help.
Here is a what I would do. I will surely add some comments.
This is running fine in Oracle 11Gr2 and I am hoping it will run fine even in 7i :).
declare
cursor c1 is
select 'REC_1' HEader,2 Val from dual
union
select 'REC_2' HEader,1 Val from dual
union
select 'REC_3' HEader,2 Val from dual;
cursor c2 is
select 'REC_A' HEader,-1 Val from dual
union
select 'REC_B' HEader,-3 Val from dual
union
select 'REC_C' HEader,-2 Val from dual;
num_bal1 number;
num_bal2 number;
num_settle_amt number;
rec_type_c1 c1%rowtype;
rec_type_c2 c2%rowtype;
begin
Open c1;
open c2;
fetch c1 into rec_type_c1;
fetch c2 into rec_type_c2;
num_bal1 := nvl(rec_type_c1.val,0);
num_bal2 := rec_type_c2.val;
Loop
exit when c1%notfound or c2%notfound;
Loop
dbms_output.put_line('Processing ' || rec_type_c1.header || ' with ' || num_bal1);
--In your example there are only +ve for 1 and -ve for 2. But if that is not correct, check for signs and next 3 statements
num_settle_amt := least(abs(num_bal1), abs(num_bal2) );
num_bal1 := num_bal1 - num_settle_amt;
num_bal2 := num_bal2 + num_settle_amt;
dbms_output.put_line('Setteled ' || num_settle_amt || ' of ' || rec_type_c1.header || ' with ' || rec_type_c2.header );
if num_bal1 = 0 then
--Update in the table. It will not impact variable.
fetch c1 into rec_type_c1;
num_bal1 := nvl(rec_type_c1.val,0);
end if;
if num_bal2 = 0 then
--Update in the table. It will not impact variable.
fetch c2 into rec_type_c2;
num_bal2 := nvl(rec_type_c2.val,0);
end if;
End loop;
end loop;
close c1;
close c2;
end;

Netezza while loop syntax

I want to make a statement in netezza so that it waits until a statement is correct before proceeding. Any help would be appreciated - something similar to the below
WHILE (
select count(*) EVENT_DESCRIPTION from TEST_DA_CONTROL.CTRL.C_DBA_MAINTENANCE_AUDIT
where EVENT_DESCRIPTION = 'STARTED' and DATETIME_LOGGED > (select add_months(current_date,0))) = 0
LOOP
wait 5
end loop;
but I don't know the correct syntax.
Best to assign that output to a variable. I seem to recall that getting data out of an execute immediate is a little arduous in nzplsql, but there are convenient variables already available for you to use. Here I'll use ROW_COUNT.
declare
event_descriptions int;
sql varchar;
begin
event_descriptions := 1;
while event_descriptions > 0 loop
--Actual work
sql := '
select * EVENT_DESCRIPTION from TEST_DA_CONTROL.CTRL.C_DBA_MAINTENANCE_AUDIT
where EVENT_DESCRIPTION = ''STARTED'' and DATETIME_LOGGED > (select add_months(current_date,0))) = 0;';
execute immediate sql;
event_descriptions := ROW_COUNT;
end loop;
end;

Nested table loops to format data, PL/SQL

I am trying to format data returned from a cursor to JSON by looping through the records and columns without having to explicitly call on each column name. From what I've researched this vary well may not be a simple task or at least as simple as I'm trying to make it. I'm wondering if anyone else has tried a similar approach and if they had any luck.
declare
type type_cur_tab is table of employees%rowtype
index by PLS_integer;
type type_col_tab is table of varchar2(1000)
index by binary_integer;
tbl_rec type_cur_tab;
tbl_col type_col_tab;
begin
select * BULK COLLECT INTO tbl_rec
from employees;
select column_name BULK COLLECT INTO tbl_col
from all_tab_columns
where UPPER(table_name) = 'EMPLOYEES';
for i IN 1..tbl_rec.COUNT Loop
for j IN 1..tbl_col.count Loop
dbms_output.put_line(tbl_rec(i).tbl_col(j));
end loop;
end loop;
end;
It throws an error saying 'tbl_col' must be declared. I'm sure this is bc it's looking for 'tbl_col' listed inside 'tbl_rec'. Any help is greatly appreciated.
NOTE: I'm aware of the built in JSON conversion but I haven't been able to get it to as fast as I'd like so I'm trying to loop through and add the appropriate formatting along the way.
It is impossible to specify field of tbl_rec(i) in this manner.
Try this:
declare
v_cur sys_refcursor;
col_cnt number;
desc_t dbms_sql.desc_tab;
c number;
vVarchar varchar2(32000);
vNumber number;
vDate date;
v_result clob:='';
rn number:=0;
begin
--Any sql query or pass v_cur as input parameter in function on procedure
open v_cur for
select * from dual;
--------
c:=dbms_sql.to_cursor_number(v_cur);
dbms_sql.describe_columns(c => c, col_cnt => col_cnt, desc_t => desc_t);
for i in 1 .. col_cnt
loop
case desc_t(i).col_type
when dbms_types.TYPECODE_DATE then
dbms_sql.define_column(c, i ,vDate);
when dbms_types.TYPECODE_NUMBER then
dbms_sql.define_column(c, i ,vNumber);
else
dbms_sql.define_column(c, i ,vVarchar,32000);
end case;
end loop;
v_result:='{"rows":{ "row": [';
while (dbms_sql.fetch_rows(c)>0)
loop
if rn > 1 then v_result:=v_result||','; end if;
v_result:=v_result||'{';
for i in 1 .. col_cnt
loop
if (i>1) then v_result:=v_result||','; end if;
case desc_t(i).col_type
--Date
when dbms_types.typecode_date then
dbms_sql.column_value(c,i,vDate);
v_result:=v_result||' "'||desc_t(i).col_name||'" :"'||to_char(vDate,'dd.mm.yyyy hh24:mi')||'"';
--Number
when dbms_types.typecode_number then
dbms_sql.column_value(c,i,vNumber);
v_result:=v_result||' "'||desc_t(i).col_name||'" :"'||to_char(vNumber)||'"';
--Varchar - default
else
dbms_sql.column_value(c,i,vVarchar);
v_result:=v_result||' "'||desc_t(i).col_name||'" :"'||vVarchar||'"';
end case;
end loop;
v_result:=v_result||'}';
end loop;
v_result:=v_result||']}}';
dbms_output.put_line (v_result);
end;
Also you can generate XML from ref cursor with DBMS_XMLGEN package and then translate xml into json with xslt transformation.

How to select value of variable in ORACLE

Below is the SQL Server's syntax to select variable as a record
DECLARE #number AS INTEGER;
SET #number = 10;
SELECT #number;
How can I do this in ORACLE?
Thanks in advance.
Regards,
Sagar Nannaware
Edited based on comment:
One way you can access the variable value assigned by a procedure is through a function again.
Example:
CREATE OR REPLACE PROCEDURE your_procedure(out_number OUT number)
IS
BEGIN
out_number:=1;
END;
function to retrieve the procedure's output
CREATE OR REPLACE FUNCTION your_function
RETURN number
AS
o_param number;
BEGIN
o_param := NULL;
your_procedure(o_param);
RETURN o_param;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
return 0; --basically how you want to handle your errors.
END your_function;
Now you can select the output of the procedure
select your_function from dual;
Useful link how to access an Oracle procedure's OUT parameter when calling it?
If you are trying to create a variable to access anywhere in your application in oracle.
You can do it by creating function and calling it from dual.
SQL>create or replace function foo return number
as
x number;
begin
x:=1;
return 1;
end;
Function created.
SQL>select foo from dual;
FOO
----------
1
Please check following link for more details
[example link] (http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1562813956388)

Resources