Drop Redshift tables latest accessed before 2 months from current time - stored-procedures

Here is the attempted stored_procedure to drop tables that have not been accessed in last 2 months.
Information_schema.tables has all the tables that are present in our redshift cluster. admin.stl_query_archive has all the queries that have run till now.
I am trying to find all the tables that are not present in the queries that have run in the last 2 months.
CREATE OR REPLACE PROCEDURE sp_drop_tables(out_var OUT varchar(256))
-- CREATE OR REPLACE PROCEDURE sp_drop_tables_()
AS $$
DECLARE
r_c int := 0;
rec record;
tbl_rows int;
BEGIN
for rec in select distinct table_name from information_schema.tables
loop
raise info 'table_name = %', rec.table_name;
tbl_rows := 0;
select count(*) into tbl_rows from admin.stl_query_archive where endtime > getdate() - 61 and querytxt like '%'||quote_literal(rec.table_name)||'%';
if tbl_rows = 0 then
raise info 'this table is old';
end if;
end loop;
select into out_var count(*) from admin.stl_query_archive;
END;
$$ LANGUAGE plpgsql;
call sp_drop_tables()
;
My approach seems correct, only problem is that it throws the following error while running -
Error [XX000 / 500310]: [Amazon](500310) Invalid operation: Assert
----------------------------------------------- error: Assert code: 1000 context: false - Unknown
constant type to hash: 17134 query: 2122914 location: cg_hash.cpp:84 process: padbmaster [pid=124705]
-----------------------------------------------;
Can anyone help me out with this? Any feedback is greatly appreciated!

I don't think you need to use quote_literal function in LIKE criteria.

Related

Solve the syntax error with Redshift operator does not exist and add explicit casts

I am a newbie in the area of redshift data modeling and got myself into trouble with an error.ERROR:
--Final version
syntax error ERROR: operator does not exist: text | record Hint: No
operator matches the given name and argument type(s). You may need to
add explicit type casts. Where: SQL statement "SELECT 'create temp
table ' || $1 || ' as select * from' | $2 |" PL/pgSQL function "egen"
line 36 at execute statement [ErrorId:
1-61dc32bf-0a451f5e2c2639235abb8876]
I am trying to do a simple transformation that gets returned in output when the procedure is called. (As of now I got to find from the documentation we have to use either temp table or cursors to achieve this)
Pseudocode:
I am trying to restrict data to its latest one in (2019) Get the
list of managers create columns if a person is a manager or not from the list.
Return it as a result
Data looks as follows Employee Data
My Select query works fine out of the procedure, please find my complete code below.
CREATE OR REPLACE PROCEDURE EGEN(tmp_name INOUT varchar(256) )
AS $$
DECLARE
--As i have less data managed to create it as an array or please use temp or table and join it with the actual query to perform transformation
MGR_RECORD RECORD;
DATAS RECORD;
item_cnt int := 0;
V_DATE_YEAR int := 0;
BEGIN
--EXECUTE (select cast(extract(year from current_date) as integer)-3) INTO V_DATE_YEAR;
--Manager Records are stored here below
SELECT DISTINCT managerid from "dev"."public"."emp_salary" INTO MGR_RECORD;
SELECT employeeid,
managerid,
promotion,
q_bonus,
d_salary,
case when contractor = 'x'
then 'TemporaryEmployee'
else 'PermanentEmployee'
END as EmployeeType,
-- IFstatement not supported under select query
case when employeeid in (select distinct managerid FROM "dev"."public"."emp_salary" )
then 'Manager'
else 'Ordinary FTE'
END as FTETYPE
FROM "dev"."public"."emp_salary" where cast(extract(year from promotion) as int ) >= 2019 into DATAS;
--COMMIT;
tmp_name := 'ManagerUpdatedTable';
EXECUTE 'drop table if exists ' || tmp_name;
EXECUTE 'create temp table ' || 'ManagerUpdatedTable' || ' as select * from' |DATAS| ;
END;
$$ LANGUAGE plpgsql;
-- Call tests CALL EGEN('myresult'); SELECT * from myresult;
Also, additional query (Can we replace )
case when employeeid in (select distinct managerid FROM "dev"."public"."emp_salary" )
then 'Manager'
else 'Ordinary FTE'
END as FTETYPE
this transform in query to IF , if possible please provide details.
Thanks and Regards,
Gabby

Stored procedure is not getting complied

I am trying to run the below stored procedure in Oracle pl/sql. I am trying to fetch data from join in cursor using table 1 and table 2 and update the output in Table 3, however its giving me compliation error near declare. The queries are working fine.
create or replace PACKAGE BODY PKG_LOAD_BY_ROWID AS
PROCEDURE PRC_LOAD_BY_ROWID AS
DECLARE
N1 NUMBER;
VAR_ROWID_OBJECT VARCHAR2(255);
VAR_PRTY_FK VARCHAR2(255);
V_OUT_ERROR_MSG VARCHAR2(1000);
v_out_return_code number;
CURSOR C1 IS
SELECT PX.ROWID_OBJECT , A.PRTY_FK
FROM TABLE_1 PX
INNER JOIN
TABLE_2 A
ON
substr(PX.PKEY_SRC_OBJECT,8,INSTR(PX.PKEY_SRC_OBJECT,'|')+8)=A.ALT_ID_VAL
WHERE A.ALT_ID_TYP='DUMMY1' AND PX.ROWID_SYSTEM='SRC';
BEGIN
SELECT COUNT(1) INTO N1 FROM TABLE_3 WHERE SRC_SYSTEM='SRC2' AND ROWID_OBJECT IS NULL;
BEGIN
OPEN C1;
FOR i in 1..n1
LOOP
FETCH C1 INTO VAR_ROWID_OBJECT, VAR_PRTY_FK;
UPDATE TABLE3 SET ROWID_OBJECT= VAR_ROWID_OBJECT WHERE
SRC_KEY=VAR_PRTY_FK;
COMMIT;
END LOOP;
CLOSE C1;
v_out_return_code :=0;
DBMS_OUTPUT.put_line('Rowid_object updated successfully for VVA');
EXCEPTION
when others then
out_error_msg := 'Updation Error';
DBMS_OUTPUT.put_line (out_error_msg);
END;
END;
END PKG_LOAD_BY_ROWID;
However, I am getting compilation error:
Error(2,1): PLS-00103: Encountered the symbol "DECLARE" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior external language
Oracle Version:
You don't need Declare keyword for the procedure, it is only for anonymous block. Just remove declare and try it.

Convert Procedure from Oracle to DB2, Error when try to update table on runtime

Hello DB2 Experts I need your assistance in converting below Procedure to something more dynamic.
We have to update multiple sequences with max of id column for each table.
CREATE PROCEDURE mySchema.UPDATE_SEQUENCE ( )
DYNAMIC RESULT SETS 1
MODIFIES SQL DATA
----------------------------------------------------------------------
-- SQL Stored Procedure
----------------------------------------------------------------------
P1: BEGIN
DECLARE counter BIGINT;
DECLARE q VARCHAR(500);
set (counter) = (select max(N_PRI_KEY) from mySchema.myTable);
set q = 'alter sequence mySchema.mySequence RESTART WITH ' || counter;
EXECUTE IMMEDIATE q;
END P1
#
This is what I have written from the above code:
Here I want N_PRI_KEY to be dynamic and mySchema.myTable to be updated on run time with the values from the table.
CREATE OR REPLACE PROCEDURE getText ()
LANGUAGE SQL
DYNAMIC RESULT SETS 1
BEGIN
DECLARE maxval INTEGER DEFAULT 0;
CALL DBMS_OUTPUT.PUT( 'a' );
FOR vrows AS
SELECT NAME, SEQUENCENAME, TBNAME FROM MAXSEQUENCE WHERE SEQUENCENAME='ASSETSEQ'
DO
SELECT MAX(vrows.NAME) INTO maxval FROM vrow.TBNAME; -- This is where I am getting error.
EXECUTE IMMEDIATE 'ALTER SEQUENCE '||vrows.SEQUENCENAME||' RESTART WITH '|| maxval;
END FOR;
END#
This is the error that I am getting when I try to create the Procedure.
DB21034E The command was processed as an SQL statement because it was not a
valid Command Line Processor command. During SQL processing it returned:
SQL0204N "VROW.TBNAME" is an undefined name. LINE NUMBER=18. SQLSTATE=42704
When I run this line it works and inserts the max value in the TEMPOUTPUT table.
execute immediate 'INSERT INTO TEMPOUTPUT VALUES (select max('||vrow.NAME||') from '||vrow.TBNAME||')';
I have tried doing this but it did not work.
execute immediate 'ALTER SEQUENCE '||SEQUENCENAME||' RESTART WITH select max('||vrow.NAME||') from '||vrow.TBNAME;
Just for Reference - This is a procedure which is written in Oralce which is doing something similar.
declare
maxval int;
seqval int;
begin
for i in ( select ucc.column_name, s.sequence_name, uc.table_name
from user_cons_columns ucc,
user_constraints uc,
user_sequences s
where uc.constraint_name = ucc.constraint_name
and uc.constraint_type = 'P'
and ucc.position = 1
and s.sequence_name = 'SEQ_'||uc.table_name
)
loop
execute immediate 'select max('||i.column_name||') from '||i.table_name into maxval;
execute immediate 'select '||i.sequence_name||'.nextval from dual' into seqval;
dbms_output.put_line(maxval||','||seqval);
if maxval > seqval then
execute immediate 'alter sequence '||i.sequence_name||' increment by '|| ( maxval - seqval );
execute immediate 'select '||i.sequence_name||'.nextval from dual' into seqval;
execute immediate 'alter sequence '||i.sequence_name||' increment by 1';
execute immediate 'select '||i.sequence_name||'.nextval from dual' into seqval;
dbms_output.put_line(maxval||','||seqval);
end if;
end loop;
end;
Try the following instead of the row with SELECT MAX(...) where you get the error:
PREPARE S1 FROM 'SET ? = (SELECT MAX(' || vrows.NAME || ') FROM ' || vrows.TBNAME || ')';
EXECUTE S1 INTO maxval;

PL SQL Procedure Exercise

I'm not really sure how to approach this question.. I understand the basic syntax of writing a procedure. This is an exercise for a beginner database class (which seems to be at a level way above beginner)
Create a procedure to place a purchase order for a specified date based on data in the inventory report table.
Name the procedure placeorder [procedure name is important].
The procedure should take one parameter: inputDate (use the datatype of the PODate column in PURCHASEORDERS). The input date format accepted should be: 'DD-MON-YYYY', e.g., 01-JAN-2017.
For each raw material in the Inventory Report table (where: ReportDate matches inputDate), make a separate entry in the PURCHASEORDERS table for a next-day delivery order and a same-day delivery order (each raw material may generate up to 2 inserts).
Corresponding order type should be either next_day or same_day
Only make an entry (insertion) in PURCHASEORDERS if needed, i.e., if
an entry exists for a raw material and report date combination in the
Inventory Report table. If the Inventory Report for a day (e.g.,
30-NOV-2017) has a 0 value for the ordersameday attribute, it means
no same_day order is needed.
If no order is needed for the provided input date (i.e., no order at all across ALL raw materials), raise an application error with a message: “no order needed” (see Triggers and Procedures tutorial on D2L for an example of how to raise this error). You can use any suitable error-number.  Your procedure should leave the “Price” (for the purchase order) empty (i.e., it can remain null). Assume it’ll be populated later.
Thanks!
Sorry this is what i've written so far.. #kara
CREATE OR REPLACE PROCEDURE placeorder (inputDate in DATE)
AS
new_inputDate PURCHASEORDERS.PODate%TYPE;
new_orderType PURCHASEORDERS.ORDERTYPE%TYPE;
c_orderSameDay INVENTORYREPORT.ORDERSAMEDAY%TYPE;
c_orderNextDay INVENTORYREPORT.ORDERNEXTDAY%TYPE;
CURSOR C1 IS
SELECT REPORTDATE INTO inputDate FROM dual;
SELECT ir.itemId, ir.ORDERSAMEDAY, ir.ORDERNEXTDAY FROM INVENTORYREPORT
WHERE
ir.REPORTDATE = inputDate;
BEGIN
OPEN C1;
WHILE C1%FOUND LOOP
FETCH C1 INTO new_inputDate, new_orderType, c_orderSameDay, c_orderNextDay;
IF c_orderSameDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderSameDay);
ELSE <application error>;
END IF;
IF c_orderNextDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderNextDay);
ELSE <application error>;
END IF;
END LOOP;
CLOSE C1;
END;
/
#kara I added to the if statements but still getting a couple errors when trying to compile the procedure. It this doing what it's supposed to be doing?
CREATE OR REPLACE PROCEDURE placeorder (inputDate in DATE)
AS
new_inputDate PURCHASEORDERS.PODate%TYPE;
new_orderType PURCHASEORDERS.ORDERTYPE%TYPE;
c_orderSameDay INVENTORYREPORT.ORDERSAMEDAY%TYPE;
c_orderNextDay INVENTORYREPORT.ORDERNEXTDAY%TYPE;
CURSOR C1 IS
SELECT REPORTDATE INTO inputDate FROM dual;
SELECT ir.itemId, ir.ORDERSAMEDAY, ir.ORDERNEXTDAY FROM INVENTORYREPORT
WHERE
ir.REPORTDATE = inputDate;
BEGIN
OPEN C1;
WHILE C1%FOUND LOOP
FETCH C1 INTO new_inputDate, new_orderType, c_orderSameDay, c_orderNextDay;
IF c_orderSameDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderSameDay);
ELSE INSERT INTO PURCHASEORDERS (new_orderType) VALUES ('no order needed');
END IF;
IF c_orderNextDay > 0
THEN INSERT INTO PURCHASEORDERS (new_orderType) VALUES (orderNextDay);
ELSE INSERT INTO PURCHASEORDERS (new_orderType) VALUES ('no order needed');
END IF;
FETCH C1 INTO new_inputDate, new_orderType, c_orderSameDay, c_orderNextDay;
END LOOP;
CLOSE C1;
COMMIT;
END placeorder;
/
There are a bunch of examples how to create a procedure. Here a small one:
CREATE OR REPLACE PROCEDURE ProcName (paraName IN VARCHAR2)
AS
myStringVariable VARCHAR2 (4000);
myDateVariable DATE;
BEGIN
SELECT orderDateAsString
INTO myStringVariable
FROM orders
WHERE orderId = paraName;
myDateVariable := TO_DATE (myStringVariable, 'dd.mm.yyyy HH24:MI:SS'); -- '13.03.2018 23:59:59'
dbms_output.put_line('My date: ' || myStringVariable);
END;
And some example-code, to call the procedure:
begin
ProcName('1234');
end;
But you should look at your exercise first and think about you tasks. I think, this is what you got to do:
Create a Table.
Create Insert-Statements for the table
Create some PL/SQL-code which performs the insert with conditions.
move the PL/SQL-code to a procedure.
Call the procedure with a PL/SQL-block.
Explaination for you edits
You should build your code step-by-step if. You got multiple errors.
Check you Cursor. The Select-statement is not valid.
You wrote two selects.
You do not use new_inputdate. Why did you define it and what should it do?
Run you SELECT-statement alone without your code. if you like your data you can put it in an cursor.
Example with your code:
CREATE OR REPLACE PROCEDURE placeorder (inputDate IN DATE)
AS
-- new_inputDate PURCHASEORDERS.PODate%TYPE; --you don't use this one
new_orderType PURCHASEORDERS.ORDERTYPE%TYPE;
c_orderSameDay INVENTORYREPORT.ORDERSAMEDAY%TYPE;
c_orderNextDay INVENTORYREPORT.ORDERNEXTDAY%TYPE;
-- you mixed up your cursors. seems like you didn't try the select-statement alone..
CURSOR C2
IS
SELECT ir.itemId, ir.ORDERSAMEDAY, ir.ORDERNEXTDAY
FROM INVENTORYREPORT
WHERE ir.REPORTDATE = inputDate;
BEGIN
OPEN C2;
WHILE C2%FOUND
LOOP
FETCH C2 INTO new_orderType, c_orderSameDay, c_orderNextDay;
NULL; -- Do something
END LOOP;
CLOSE C2;
END;
/
Think about what you want to do in the loop. Build a small skript with the variables and think about what it should do:
Example-Skript of you Loop-content:
DECLARE
-- new_inputDate PURCHASEORDERS.PODate%TYPE; --you don't use this one
new_orderType NUMBER := 0;
c_orderSameDay NUMBER := 1;
c_orderNextDay NUMBER := 2;
BEGIN
-- this is what you're doing in you loop.
IF c_orderSameDay > 0 -- check if c_orderSameDay is greater than 0? In Oracle you use 'NULL' as empty value. Perhaps it should be 'c_orderSameDay IS NOT NULL'
THEN
INSERT INTO PURCHASEORDERS (new_orderType) -- you perform your insert.
VALUES (orderSameDay);
ELSE
RAISE; -- you raise an exception? this means c_orderSameDay has alsway to be set.
END IF;
IF c_orderNextDay > 0
THEN
INSERT INTO PURCHASEORDERS (new_orderType)
VALUES (orderNextDay);
ELSE
RAISE; -- you raise an exception? this means c_orderNextDay has alsway to be set.
END IF;
END;

PL/SQL:, How to pass variable into SELECT statent and return all rows of results

I am using an oracle database. I am used to SQL server but not familiar with PL/SQL for the Oracle database.
How do I Set a variable that returns all the rows that contain the value of that variable: I am lost, I tried to understand, but it is not making sense to me. This si a recent attempt I made to to this.
DECLARE date1 varchar(40);
Begin
Select '''07/31/2013_09%''' into :date1 from dual;
End;
/
print date1
Begin
Select * from TABLE1 where start_time LIKE date1;
End;
/
I should get all the rows returned from this.
Thank you for your help.
This might help you get started:
create table table1 (
start_time varchar2(10),
foo number
);
insert into table1 values ('xyz', 1);
insert into table1 values ('wxy', 2);
insert into table1 values ('abc', 3);
create type table1_obj as object (
start_time varchar2(10),
foo number
);
/
create type table1_tab as table of table1_obj;
/
declare
v table1_tab;
begin
select table1_obj(start_time, foo) bulk collect into v
from table1 where start_time like '%x%';
end;
/
You have to create a parametrized cursor and pass that date as parameter to that cursor as below.
CREATE or REPLACE procedure proc1(p_date date)
as
CURSOR C1 (date1 date)is
SELECT * from TABLE1 where start_time LIKE date1;
BEGIN
FOR i in c1(p_dat)
LOOP
.......
END LOOP;
END;
It looks like you're missing the understanding of several basic building blocks:
You need a PL/SQL data structure where you'll save the data set queried from database table: PL/SQL Collections and Records. See especially nested tables and record variables.
You query the database with PL/SQL Static SQL. See especially SELECT INTO statements. In this case there is no need for dynamic SQL.
But of course it is bit harder to get a set of rows out of the database than only one row. Here the keywords are: SELECT INTO Statement with BULK COLLECT Clause. Note that depending on your query and table size bulk collection will potentially exhaust your server's memory (by loading millions of rows).
Here is an example that should give you a kickstart:
create table so26 (
day date,
event varchar(10)
);
insert all
into so26 values(trunc(sysdate - 1), 'foo1')
into so26 values(trunc(sysdate - 1), 'foo2')
into so26 values(trunc(sysdate - 1), 'foo3')
into so26 values(trunc(sysdate ), 'bar')
into so26 values(trunc(sysdate + 1), 'zoo')
select 1 from dual;
select * from so26;
declare
type event_list_t is table of so26%rowtype;
v_events event_list_t := event_list_t();
function get_events(p_day in date default sysdate) return event_list_t as
v_events event_list_t := event_list_t();
begin
select *
bulk collect into v_events
from so26
where day = trunc(p_day);
return v_events;
end;
begin
v_events := get_events(sysdate + 1);
if v_events.first is null then
dbms_output.put_line('no events on that day');
return;
end if;
for i in v_events.first .. v_events.last loop
dbms_output.put_line(i || ': event = ' || v_events(i).event);
end loop;
end;
/
Example output when get_events(sysdate - 1):
1: event = foo1
2: event = foo2
3: event = foo3

Resources