Is there anyway to run multiple-procedures back-to-back in PL/SQL so that a table is created and then filled in as structured in my code? - stored-procedures

I am working with Oracle SQL Developer and I am trying get the below code to work and just can't figure it out. I have tried multiple different methods including implementing for loops, execute immediate's, scheduling and recompiling.
BEGIN
ORDER_STATUS_1_DROP_TABLE; -- If the table exist, drop it
ORDER_STATUS_2_CREATE_TABLE; -- Create the table
GRANT_NEWANALYTICS; -- Grant users select access
ORDER_STATUS_3_SCRIPT; -- Run script to insert data into table
END;
What the code is trying to do is this:
Procedure 1: Drop if exist, otherwise skip. I don't want to see any warning errors stating that no table exist if this procedure is run when there is no table. This procedure by itself does work as intended.
create or replace PROCEDURE ORDER_STATUS_1_DROP_TABLE IS
table_does_not_exist EXCEPTION;
PRAGMA EXCEPTION_INIT(table_does_not_exist, -942);
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE <Table Name>';
EXCEPTION
WHEN table_does_not_exist then
dbms_output.put_line( 'table dose not exist');
END ORDER_STATUS_1_DROP_TABLE;
Procedure 2: Once the table is dropped, this procedure recreates it with the correct . I don't want to see any errors for "this table already exist" and that is why, in part, procedure 1 exists. This by itself works as intended.
create or replace PROCEDURE ORDER_STATUS_2_CREATE_TABLE IS
v_sql LONG;
BEGIN
v_sql:= 'create table <Table Name>
(<parameters>)';
EXECUTE IMMEDIATE v_sql;
END ORDER_STATUS_2_CREATE_TABLE;
Procedure 3: This just gives users select access to the table created in the last procedure. This procedure works as it was intended.
create or replace PROCEDURE GRANT_NEWANALYTICS IS
BEGIN
EXECUTE IMMEDIATE
'GRANT SELECT ON <Table Name> TO <UserID>';
END;
Procedure 4: This is a complicated query. It is an insert select all from (table left join to a few other tables based upon fields and conditions, etc). After procedures 1-3 are run, this procedure by itself has not issue running, but by itself.
create or replace PROCEDURE ORDER_STATUS_3_SCRIPT IS
BEGIN
DELETE FROM <Table Name>;
INSERT INTO <Table Name>
SELECT * FROM(<Multiple Table Joins>);
END ORDER_STATUS_3_SCRIPT;
When I run the procedures like this:
BEGIN
ORDER_STATUS_1_DROP_TABLE; -- If the table exist, drop it
ORDER_STATUS_2_CREATE_TABLE; -- Create the table
GRANT_NEWANALYTICS; -- Grant users select access
ORDER_STATUS_3_SCRIPT; -- Run script to insert data into table
END;
I get the following error report:
Error report -
ORA-04068: existing state of packages has been discarded
ORA-04065: not executed, altered or dropped stored procedure "<user>.ORDER_STATUS_3_SCRIPT"
ORA-06508: PL/SQL: could not find program unit being called: "<user>.ORDER_STATUS_3_SCRIPT"
ORA-06512: at line 5
04068. 00000 - "existing state of packages%s%s%s has been discarded"
*Cause: One of errors 4060 - 4067 when attempt to execute a stored procedure.
*Action: Try again after proper re-initialization of any application's state.
Now, If I run these separately, it works. So if I first run this:
BEGIN
ORDER_STATUS_1_DROP_TABLE; -- If the table exist, drop it
ORDER_STATUS_2_CREATE_TABLE; -- Create the table
GRANT_NEWANALYTICS; -- Grant users select access
END;
<OUTPUT> PL/SQL procedure successfully completed.
And then this:
BEGIN
ORDER_STATUS_3_SCRIPT; -- Run script to insert data into table
END;
<OUTPUT> <Query runs>
I have not issues. I want to run these set of procedures in ones sweep and could use some help on the idea of such. Anyone have any ideas?

If you want to run all these procedures as a part of a single PL/SQL block then every reference to your table would need to be via dynamic SQL. So ORDER_STATUS_3_SCRIPT would need to use dynamic SQL to build the insert statement(s) to populate the table rather than using simple static SQL. That's obviously possible but it does increase the complexity of the script. Potentially substantially.
Having two PL/SQL blocks, which you've demonstrated works, seems much simpler.

Related

Rename 2 tables within the same stored procedure

I have written a stored procedure to rename a table to old and rename the temp table current in the same procedure so that users don't see an empty table while the temp table is loading. Each execute immediate does rename both tables, however I get an error saying sql command not properly executed. If I commit each of the executes, the procedure runs without issue. Am i getting this error because I cannot rename one procedure to another one in the same procedure or is there something else I am missing?
Any assistance would be greatly appreciated!
Here is my program:
CREATE OR REPLACE PROCEDURE RENAME_TABLE
IS
BEGIN
EXECUTE IMMEDIATE
('ALTER TABLE CURRENT_TABLE RENAME TO CURRENT_TABLE_OLD');
--rename current table to old
DBMS_OUTPUT.PUT_LINE ('rename current to old');
COMMIT;
EXECUTE IMMEDIATE
('ALTER TABLE CURRENT_TABLE_TMP RENAME TO CURRENT_TABLE');
--rename tmp table to current
DBMS_OUTPUT.PUT_LINE ('rename tmp to current');
EXCEPTION
WHEN OTHERS
THEN
-- There was a problem somewhere. Display the error code.
DBMS_OUTPUT.PUT_LINE (
'Exception raised during RENAME_TABLE'
|| TO_CHAR (SQLCODE)
|| ' - '
|| SUBSTR (SQLERRM, 1, 200));
END;
/

Integration through procedure Oracle

I would like to integrate with OSB keeping my logic in the DB. To minimize bandwidth load and calls to DB I would like to batch insert records through a Stored Procedure.
my goal -> avoid loops on procedure, avoid cursor, avoid multi call to DB.
In TSQL I would have done this through Table type parameter, but as this is not possible in PLSQL I have created the following script that gives me error on parameter select in the package body. Can anyone help me?:
--create type object
create or replace TYPE "Type_test" IS OBJECT (
id number(20,0)
oppdateringstype VARCHAR2(50)
)
;
-- Create package head
create or replace package test as
type t_input_table is table of Type_test index by binary_integer;
procedure Proc (p_input_table in t_input_table);
end;
--Create package body
create or replace package body test as
procedure Proc(p_input_table in t_input_table)
as
BEGIN
--Some logic select * from p_input_table
end;

While executing simple stored procedure getting warning compiled but compilation error how to see

While executing a simple stored procedure getting a warning compiled but compilation error how to see.
Below is the query:
create procedure spgetdat
as
begin
select empis empname, empadd from tb1employees;
end;
While executing above query getting an error. Pls suggest what needs to be corrected.
Regards
Jitendra
Your Select statement inside the procedure is not correct. There should be into clause in the select statement inside the PL/SQL block.
It can be like below. You have to put a where condition for selection of one record or for best practice you can use cursor to fetch more then one record also.
create procedure spgetdat
as
v_empis tab1employees.empis%type;
v_empadd tab1employees.empadd%type;
begin
select empis empname ,empadd into v_empis,v_empadd from tb1employees where empis = 'given name' ;
end;
show errors;

DB2 - How do I create a Stored Procedure that ignores errors?

I am trying to create a simple stored procedure in DB2 that performs the following actions:
Drop table "DELETE_ME"
Create table "DELETE_ME"
Insert into table "DELETE_ME"
Basically, if the table DELETE_ME already exists, the stored procedure executes fine. If it does not exist, then the Stored Procedure fails with the following error:
Lookup Error - DB2 Database Error: ERROR [42704] [IBM][DB2/LINUXX8664] SQL0204N "SARTS02T.DELETE_ME" is an undefined name.
I completely understand this. However, I was hoping to set the procedure up to ignore this error (and all errors) that way the procedure can work as a deployment script as well. On the first deployment, it will ignore the drop table line and jump right to building the table.
I found a CREATE PROCEDURE option called CONTINUE AFTER FAILURE however I am receiving an error. Please see my code and error below. Thanks for your help!!!
CODE:
CREATE OR REPLACE PROCEDURE TEST_PROC LANGUAGE SQL CONTINUE AFTER FAILURE
BEGIN
DROP TABLE DELETE_ME;
CREATE TABLE DELETE_ME (
COLUMN_A DECIMAL(5)
);
INSERT INTO DELETE_ME (COLUMN_A) VALUES (69);
COMMIT;
END;
ERROR:
Lookup Error - DB2 Database Error: ERROR [42601] [IBM][DB2/LINUXX8664] SQL0104N An unexpected token "CONTINUE AFTER FAILURE" was found following "ST_PROC LANGUAGE SQL". Expected tokens may include: "<space>".
The BEGIN ... END section is called a compound statement which allows various declarations and other statements, including other compound statements, to be included inside it.
You'll want to declare a condition handler. You could do it something like this.
CREATE OR REPLACE PROCEDURE TEST_PROC
LANGUAGE SQL
COMMIT ON RETURN YES
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' -- or SQLEXCEPTION
BEGIN
-- insert any code here when DROP fails
END;
DROP TABLE DELETE_ME;
CREATE TABLE DELETE_ME
( COLUMN_A DECIMAL(5)
);
INSERT INTO DELETE_ME (COLUMN_A)
VALUES (69);
END;

Saving deleted records to another table

I am deleting records from one table (based on a condition) like :
procedure TForm3.AdvGlowButton1Click(Sender: TObject);
begin
if MessageDlg('Are you sure???' , mtConfirmation, [mbYes, mbNo], 0) = mrNo then
Abort else
Case cxRadioGroup1.ItemIndex of
0: begin
with Form1.ABSQuery1 do begin
Form1.ABSQuery1.Close;
Form1.ABSQuery1.SQL.Clear;
Form1.ABSQuery1.SQL.Text :='delete from LOG where status="YES" ';
Form1.ABSQuery1.ExecSQL;
Form1.ABSTable1.Refresh;
end;
end;
End;
end;
However,I want to save these deleted records in another table that I have created for the purpose (LOG_ARCHIVE) which is identical to the LOG table. So how do I save these deleted records over there ?
If you were using a database that supported it, you could use a BEFORE DELETE trigger. However, according to a search on the Absolute Database documentation, there's no support for CREATE TRIGGER and a search on triggers at the same site returns nothing about them either.
The lack of trigger support probably just leaves you with performing an INSERT into the other table first, before doing the DELETE from your LOG table. According to the documentation again, a query is able to be used as the source of data for an INSERT (see the second example on the linked page). This means you can do something like this:
ABSQuery1.SQL.Text := 'insert into LOG_ARCHIVE'#13 +
'(select * from LOG where status = ''Yes'')';
ABSQuery1.SQL.ExecSQL;
ABSQuery1.Close;
{
No need to use SQL.Clear here. Setting the SQL.Text replaces
what was there before with new text.
}
ABSQuery1.SQL.Text :='delete from LOG where status=''YES''';
ABSQuery1.ExecSQL;
You really should wrap this entire operation in a transaction (Delphi example here), so that in case something fails both the INSERT and DELETE can be undone. (For instance, if the INSERT works putting the rows in the LOG_ARCHIVE file, but the DELETE then fails for some reason, you have no way to remove the rows you inserted into the archive file.) A transaction can be started before you do the INSERT, rolled back if it (or the DELETE fails or committed if both of them succeed.

Resources