Snowflake script: accumulate result sets in for loop? - sql

I wrote a Snowflake script with a for loop to drop all "old" schemas in a database:
DECLARE
rs RESULTSET;
curs CURSOR FOR (
select * from information_schema.schemata
where last_altered < dateadd(day, -7, current_timestamp())
);
BEGIN
FOR record IN curs DO
rs := (EXECUTE IMMEDIATE 'drop schema if exists ' || record.schema_name || ';') ;
END FOR;
RETURN table(rs);
END;
I'm happy with this except that what it returns is only the result of the last query.
Of course this is expected because I'm not aggregating the results in rs inside the for loop, I'm merely overwriting rs.
I'm struggling to write something to store the results statuses in a table and return that at the end. Some help would be great.

Using temporary table as an intermediate storage for DDL output:
DECLARE
rs RESULTSET;
curs CURSOR FOR (
select *
from information_schema.schemata
where schema_name NOT IN ('INFORMATION_SCHEMA', 'PUBLIC')
and last_altered < dateadd(day, -7, current_timestamp())
);
BEGIN
CREATE OR REPLACE TEMPORARY TABLE PUBLIC.result_table(output TEXT);
FOR record IN curs DO
EXECUTE IMMEDIATE 'drop schema if exists ' || record.schema_name || ';';
INSERT INTO PUBLIC.result_table(output)
SELECT "status"
FROM TABLE(RESULT_SCAN(LAST_QUERY_ID(-1)));
END FOR;
rs := (SELECT * FROM PUBLIC.RESULT_TABLE);
RETURN TABLE(rs);
END;
Output:

Related

COPY Variant into S3 from Snowflake

Attached picture is my source data in a Snowflake table. I need to copy this into S3 as 2 individual files.
EXECUTE IMMEDIATE
$$
DECLARE
load_dt_tss timestamp;
file_name varchar2(30);
c1 CURSOR FOR SELECT DISTINCT RECORD_CONTENT, LOAD_DT_TS FROM mytable where LOAD_DT_TS >= '2022-02-09 00:00:00';
BEGIN
for record in c1 do
load_dt_tss:=RECORD.LOAD_DT_TS;
file_name:=load_dt_tss||'.csv';
EXECUTE IMMEDIATE 'copy into #STG_SF_S3/'||:file_name|| 'from (select record_content from mytable where LOAD_DT_TS >= ''2022-02-09 00:00:00'') FILE_FORMAT = (TYPE=JSON,COMPRESSION = NONE) single = FALSE overwrite=FALSE';
end for;
RETURN 0;
END;
$$ ;
Above given is the Query I'm using. When running this query, I get Error as:
"Uncaught exception of type 'STATEMENT_ERROR' on line 10 at position 3 : SQL compilation error: syntax error line 1 at position 40 unexpected '21' ".
Can someone please help.
CREATE database AAP_LDS_DEV_DB;
create schema AAP_LDS_DEV_DB.PURCHASE_ORDER;
create table AAP_LDS_DEV_DB.PURCHASE_ORDER.T_PO_STG(RECORD_CONTENT variant, LOAD_DT_TS timestamp_ntz );
insert into AAP_LDS_DEV_DB.PURCHASE_ORDER.T_PO_STG (SELECT parse_json(column1), to_timestamp(column2) from values
('{"blar":"blar1"}','2022-02-10'),
('{"blar":"blar2"}','2022-02-11')
);
EXECUTE IMMEDIATE
$$
DECLARE
sql text;
file_name text;
c1 CURSOR FOR SELECT DISTINCT RECORD_CONTENT, LOAD_DT_TS FROM AAP_LDS_DEV_DB.PURCHASE_ORDER.T_PO_STG where LOAD_DT_TS >= '2022-02-09 00:00:00';
BEGIN
for record in c1 do
file_name := to_char(RECORD.LOAD_DT_TS, 'yyyymmdd_hhmmss') || '.csv';
sql := 'copy into #STG_SF_S3_DEV_JJC/' || :file_name || ' from (select record_content from AAP_LDS_DEV_DB.PURCHASE_ORDER.T_PO_STG where LOAD_DT_TS = ''' || RECORD.LOAD_DT_TS || ''') FILE_FORMAT = (TYPE=JSON,COMPRESSION = NONE) single = FALSE overwrite=FALSE';
EXECUTE IMMEDIATE sql;
end for;
RETURN 0;
END;
$$ ;
EXECUTE IMMEDIATE
$$
DECLARE
file_name varchar2(30);
records variant;
c1 CURSOR FOR SELECT DISTINCT RECORD_CONTENT, LOAD_DT_TS FROM mytable where LOAD_DT_TS >= '2022-02-09 00:00:00';
BEGIN
for record in c1 do
file_name := 'PO'||'_'||to_date(RECORD.LOAD_DT_TS)||'_'||TO_TIME(RECORD.LOAD_DT_TS)||'.json';
records := RECORD.record_content;
create or replace temporary table temp_test_pvt(records variant);
insert into temp_test_pvt select parse_json(:records) ;
EXECUTE IMMEDIATE 'copy into #STG_SF_S3/' || :file_name ||
' from (select distinct records from temp_test_pvt)
FILE_FORMAT = (TYPE=JSON, COMPRESSION = NONE) single = true overwrite=FALSE detailed_output = TRUE ';
end for;
RETURN 0;
END;
$$ ;
This is my final query. With this I am able to COPY one record as one file from Snowflake table into S3.

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;
/

Dynamic Oracle Procedure - issue with structure

I seem to be having some issues around creating a stored procedure and I simply cannot see where the issue lies. I am relatively new to Oracle.
I have a table of unknown length. What I have done is I created a stored procedure that will create a table to the width of the row count of the table where I am getting my values from. i.e. if the table has 10 values, the code will create a new table 10 columns wide, etc.
I have managed to get the initial code working, but now I am trying to add some additional logic without success.
My logic that I am trying to accomplish is as such:
IF TABLE DOES NOT EXIST - CREATE IT
IF TABLE EXSITS - SIMPLY INSERT INTO IT
I have not created the code for the INSERT part yet as I cannot get the first part to work. Everything was working fine until I added the count and IF statement.
CREATE OR REPLACE PROCEDURE "MDWPROD"."WORKFLOW_VAR_PIVOT" IS
v_sql varchar2(32767);
-- for the first run ofthe procedure, we need to create the table
DECLARE var_count INT;
SELECT
COUNT(*)
INTO
var_count
FROM
all_tables
WHERE
OWNER = 'MDWPROD'
AND TABLE_NAME = 'RBI_PROCESSVARIABLE_WK';
-- if var_count = 0 then the table does not exists, create it, otherwise proceed with other logic
IF var_count = 0 THEN
-- cursor to find out the maximum number of projected columns required
CURSOR cur_proj_test IS
SELECT DISTINCT
ID,
VARIABLE_REPORT_LBL
FROM
MDWPROD.RBI_VARIABLETYPE_DM
ORDER BY
ID;
-- We now loop through the cursor, and build of the SQL string to CREATE and POPULATE the table
BEGIN
v_sql := 'CREATE TABLE MDWPROD.RBI_PROCESSVARIABLE_WK AS SELECT VAR.PROCESS_ID';
FOR i IN cur_proj_test
LOOP
-- dynamically add to the projection for the query
v_sql := v_sql || ',MAX(CASE VT.VARIABLE_REPORT_LBL WHEN ''' || i.VARIABLE_REPORT_LBL || ''' THEN VAR.VALUE ELSE '''' END) AS "' || i.VARIABLE_REPORT_LBL || '"';
END LOOP;
v_sql := v_sql || ' FROM MDWPROD.RBI_VARIABLE_DM VAR INNER JOIN MDWPROD.RBI_VARIABLETYPE_DM VT ON VAR.VARIABLE_TYPE_ID = VT.ID WHERE VAR.CURRENT_IND = ''Y'' GROUP BY VAR.PROCESS_ID order by VAR.PROCESS_ID';
-- Create table and populate it with all the relevant variable values
EXECUTE IMMEDIATE v_sql;
END;
END IF;
END;
Any assistance would be greatly appreciated.
Original working proc:
CREATE OR REPLACE PROCEDURE WORKFLOW_VAR_PIVOT IS
v_sql varchar2(32767);
-- cursor to find out the maximum number of projected columns required
CURSOR cur_proj_test IS
SELECT DISTINCT
ID,
VARIABLE_REPORT_LBL
FROM
MDWPROD.RBI_VARIABLETYPE_DM
ORDER BY
ID;
-- We now loop through the cursor, and build of the SQL string to CREATE and POPULATE the table
BEGIN
v_sql := 'CREATE TABLE MDWPROD.RBI_PROCESSVARIABLE AS SELECT VAR.PROCESS_ID';
FOR i IN cur_proj_test
LOOP
-- dynamically add to the projection for the query
v_sql := v_sql || ',MAX(CASE VT.VARIABLE_REPORT_LBL WHEN ''' || i.VARIABLE_REPORT_LBL || ''' THEN VAR.VALUE ELSE '''' END) AS "' || i.VARIABLE_REPORT_LBL || '"';
END LOOP;
v_sql := v_sql || ' FROM MDWPROD.RBI_VARIABLE_DM VAR INNER JOIN MDWPROD.RBI_VARIABLETYPE_DM VT ON VAR.VARIABLE_TYPE_ID = VT.ID WHERE VAR.CURRENT_IND = ''Y'' GROUP BY VAR.PROCESS_ID order by VAR.PROCESS_ID';
-- un comment this line to print out the entire SQL statement
-- dbms_output.put_line('Dynamic SQL Statement:-' || chr(10) || v_sql || chr(10) || chr(10));
-- DROP TABLE before recreating it
EXECUTE IMMEDIATE 'DROP TABLE MDWPROD.RBI_PROCESSVARIABLE';
-- Create table and populate it with all the relevant variable values
EXECUTE IMMEDIATE v_sql;
END;
There may be other problems (you never stated your exact error), but I can immediately see that the begin keyword is in the wrong place. Your declarations should be at the top, before the begin keyword, and your execution statements should come after.
I moved things around a little. This should get you closer to your goal:
CREATE OR REPLACE PROCEDURE "MDWPROD"."WORKFLOW_VAR_PIVOT" IS
v_sql varchar2(32767);
-- for the first run ofthe procedure, we need to create the table
DECLARE var_count INT;
-- cursor to find out the maximum number of projected columns required
CURSOR cur_proj_test IS
SELECT DISTINCT
ID,
VARIABLE_REPORT_LBL
FROM
MDWPROD.RBI_VARIABLETYPE_DM
ORDER BY
ID;
BEGIN
SELECT
COUNT(*)
INTO
var_count
FROM
all_tables
WHERE
OWNER = 'MDWPROD'
AND TABLE_NAME = 'RBI_PROCESSVARIABLE_WK';
-- if var_count = 0 then the table does not exists, create it, otherwise proceed with other logic
IF var_count = 0 THEN
-- We now loop through the cursor, and build of the SQL string to CREATE and POPULATE the table
v_sql := 'CREATE TABLE MDWPROD.RBI_PROCESSVARIABLE_WK AS SELECT VAR.PROCESS_ID';
FOR i IN cur_proj_test
LOOP
-- dynamically add to the projection for the query
v_sql := v_sql || ',MAX(CASE VT.VARIABLE_REPORT_LBL WHEN ''' || i.VARIABLE_REPORT_LBL || ''' THEN VAR.VALUE ELSE '''' END) AS "' || i.VARIABLE_REPORT_LBL || '"';
END LOOP;
v_sql := v_sql || ' FROM MDWPROD.RBI_VARIABLE_DM VAR INNER JOIN MDWPROD.RBI_VARIABLETYPE_DM VT ON VAR.VARIABLE_TYPE_ID = VT.ID WHERE VAR.CURRENT_IND = ''Y'' GROUP BY VAR.PROCESS_ID order by VAR.PROCESS_ID';
-- Create table and populate it with all the relevant variable values
EXECUTE IMMEDIATE v_sql;
END IF;
END;

Oracle - iterate over tables and check for values in attribute

For all tables in X, while X is
select table_name from all_tab_cols
where column_name = 'MY_COLUMN'
and owner='ADMIN'
I need to check, if the column MY_COLUMN has other values than 'Y' or 'N' and if it does, print out the table name.
Pseudo code:
for table in X:
if MY_COLUMN !='Y' or MY_COLUMN !='N':
print table
How to implement that in PL/SQL, with cursors I guess?
Following should work:
DECLARE
counter NUMBER;
cursor c1 is
select table_name from all_tab_cols
where column_name = 'MY_COLUMN'
and owner='ADMIN';
BEGIN
FOR rec IN c1 LOOP
DBMS_OUTPUT.PUT_LINE(rec.table_name);
EXECUTE IMMEDIATE 'select count(*) into :counter from '|| rec.table_name ||' where MY_COLUMN!= ''Y'' and MY_COLUMN!= ''N'' ';
if counter > 0 then
DBMS_OUTPUT.PUT_LINE(rec.table_name);
end if;
END LOOP;
END;
Basically we open a cursor with all tables containing that column, do a count for rows that have different values than Y or N, and if that count > 0, print the table.
The version of Wouter does not work for me.
Had to remove the semicolon (Oracle Database version 11.2.0.4.0 )
DECLARE
counter NUMBER;
BEGIN
select count(*) into counter from LASTID;
dbms_output.put_line(counter);
END;
/

Cursor and table cannot be found

I have a procedure that will select MAX from some tables, but for some reason it is not able to find these tables. Could anybody help me?
declare
varible1 varchar2 (255);
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols order by table_name;
begin
FOR asd in c1
LOOP
temp := asd.table_name;
varible1 := '"'||temp||'"';
select max("id") into last_val from varible1 ;
END LOOP;
end;
For example, the first table name is acceptance_form and for select I need to use "acceptance_form".
Code after edit:
declare
varible1 varchar2 (255);
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols where column_name = 'id';
begin
FOR asd in c1
LOOP
temp := asd.table_name;
execute immediate 'select NVL(max('||'id'||'),0) from "'||varible1||'"' into last_val;
END LOOP;
end;
Can't cuz db is Case sensitive Oracle express 10g tables and rows was created like this
CREATE TABLE "ADMINMME"."acceptance_form"
(
"group_id" NUMBER(9, 0),
"id" NUMBER(4, 0) DEFAULT '0' NOT NULL ,
"is_deleted" NUMBER(4, 0),
"name" NVARCHAR2(30) NOT NULL
);
Can u tell me how to handle exception sequence dosn't exist for this;
Nevermind exception was in wrong block :)
declare
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols where column_name = 'id';
begin
FOR asd in c1
LOOP
temp := asd.table_name;
execute immediate 'select NVL(max("id"),0)+1 from "'||temp||'"' into last_val;
begin
EXECUTE IMMEDIATE 'drop sequence "seq_'|| temp||'"';
EXECUTE IMMEDIATE 'create SEQUENCE "seq_'|| temp ||'" MINVALUE '||last_val||'MAXVALUE 999999999999999999999999999 INCREMENT BY 1 NOCACHE';
EXECUTE IMMEDIATE 'select '||temp||'.nextval from dual';
EXECUTE IMMEDIATE 'ALTER SEQUENCE "seq_'||temp||'" INCREMENT BY 1';
exception when others then
null;
end;
END LOOP;
end;
Dynamic sql doesn't work in that way.
declare
varible1 varchar2 (255);
temp varchar2 (255);
last_val number(9,0);
cursor c1 is Select distinct table_name from user_tab_cols order by table_name;
begin
FOR asd in c1
LOOP
temp := asd.table_name;
begin
execute immediate 'select max(id) from '||temp into last_val;
dbms_output.put_line('max(id) for table: ' ||temp||' = '||last_val);
exception when others then
dbms_output.put_line('Failed to get max(id) for table: ' ||temp);
end;
END LOOP;
end;
You can't use a variable for the table name.
What you can do is creating the complete sql statement as a string and use execute immediate
Here are some examples how to do that: http://docs.oracle.com/cd/B19306_01/appdev.102/b14261/dynamic.htm#CHDGJEGD