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

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;

Related

Dynamic SQL calling another stored procedure in Teradata

I've seen in the help guides that you cannot use a call statement in a teradata dynamic sql statement without output parameter.
I assume this implies I can, If the proc has an output parameter.
has anyone done this?
Scenario -
I have a table that at some point I'll expand out in terms of fields for logic on when things should run, and this table is managed elsewhere -
CREATE TABLE DB.SP_Test
(
ProcName VARCHAR(250)
,ProcRun VARCHAR(1)
);
now I added chrTest as an output however, I am still getting an error on run (no compile error)
The error :-
SQL_State SQL_Exception
T7689 Invalid dynamic SQL statement.
REPLACE PROCEDURE DB.Test_Control (OUT chrTest VARCHAR(250) )
SQL SECURITY INVOKER
LMain:
BEGIN
DECLARE sqlProcRun VARCHAR(20000);
DECLARE CONTINUE HANDLER
FOR SqlException
BEGIN
-----------------------------------------------------------------------------
DECLARE strExceptionText VARCHAR(250);
GET DIAGNOSTICS EXCEPTION 1 strExceptionText = Message_Text;
INSERT INTO DB.PROC_ERROR VALUES
(
'Test_Control'
,:SqlState
,strExceptionText
,Current_Timestamp
)
;
END;
-----------------------------------------------------------------------------
SET sqlProcRun ='';
L0:
FOR procs_run_cursor AS select_list
CURSOR FOR
SELECT Trim(ProcName) AS ProcName
FROM DB.SP_Test
DO
/*creating a lost of call statements to run*/
SET sqlProcRun = sqlProcRun ||'CALL DB.'||procs_run_cursor.ProcName|| '();';
END FOR L0;
EXECUTE IMMEDIATE sqlProcRun;
END;

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?

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.

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;

How to define an Array of values (or a Column) into a Procedure Argument?

I am working on a Netezza SP and is stuck with a problem.
I have a SP, defined as say:
CREATE OR REPLACE PROCEDURE MY_PROC(VARCHAR(ANY)) RETURNS INTEGER LANGUAGE NZPLSQL
AS
BEGIN_PROC
DECLARE
v_temp ALIAS FOR $1;
/* Other decalarations */
result_ts INTEGER;
BEGIN
result_ts := 0;
/* Procedure Body */
RETURN result_ts;
EXCEPTION WHEN OTHERS THEN
RAISE NOTICE 'Exception Raised: %', SQLERRM;
END;
END_PROC;
If I am running this SP with one value, such as:
SELECT MY_PROC('TEST_INPUT');
But if I am trying to run it with a column value, such as:
SELECT MY_PROC(TEST_COLUMN) FROM TEST_TABLE;
Its giving me error as:
ERROR: Can't use a stored procedure in this context
I know that in the second scenario I am passing an Array (i guess) but this is not what the Procedure has expected.
Now I am trying to have a procedure that can accept these kind of values but could not succeeded so far, LOOPing and all I have taken care but only problem is the Argument which I don't know how to pass.
Any help would be appreciated, let me know if I need to provide any extra info on this.
Asif
Stored procedures in Netezza, as of v7.2, can only be called in the following ways, as documented here.
CALL sproc_name(...);
EXEC sproc_name(...);
SELECT sproc_name(...);
Note that the SELECT form does not allow a FROM clause.
If you want the stored procedure to act on a particular column from a particular table that changes from invocation to invocation, you could pass the names of those as arguments to the stored procedure and have the entirety of the SQL logic encoded within. You could even pass arbitrary code into the stored procedure to build a query internally.
The way you are trying to call it now is more like calling a user defined function, and that simply won't work with stored procedures here.

DB2 Can't REFRESH Materialized Query Table (MQT) in Stored Procedure

I'm having trouble refreshing an MQT inside of a stored procedure.
I'm receiving the following error when attempting to refresh the table :
ERROR [42601] [IBM][DB2/LINUXX8664] SQL0104N An unexpected token "REFRESH" was found following "ANGUAGE SQL BEGIN " . Expected tokens may include: "TRUNCATE" .
/**********
* CREATE A NEW DUMMY TABLE AND INSERT DUMMY DATA
**********/
CREATE TABLE DELETE_ME (
COLUMN_A DECIMAL(5)
);
INSERT INTO DELETE_ME (COLUMN_A) VALUES (1);
INSERT INTO DELETE_ME (COLUMN_A) VALUES (2);
INSERT INTO DELETE_ME (COLUMN_A) VALUES (3);
/**********
* CREATE A MATERIALIZED QUERY USING THE DUMMY TABLE
**********/
CREATE TABLE MQT_TEST AS (
SELECT COLUMN_A
FROM DELETE_ME
)
DATA INITIALLY DEFERRED
REFRESH DEFERRED
ENABLE QUERY OPTIMIZATION
NOT LOGGED INITIALLY;
COMMIT;
/**********
* CREATE A SIMPLE PROCEDURE TO REFRESH THE MATERIALIZED QUERY
**********/
CREATE OR REPLACE PROCEDURE TEST_PROC LANGUAGE SQL
BEGIN
REFRESH TABLE MQT_TEST;
END;
--!!!! FAILS WITH THE FOLLOWING ERROR CODE: - DB2 Database Error :
ERROR [42601] [IBM][DB2/LINUXX8664] SQL0104N An unexpected token "REFRESH" was found following "ANGUAGE SQL BEGIN ". Expected tokens may include: "TRUNCATE" .
You can't execute the REFRESH TABLE as a static statement in a stored procedure as it can only run as a dynamic statement.
Therefore, the proper method to do this is to use the EXECUTE IMMEDIATE statement:
CREATE OR REPLACE PROCEDURE TEST_PROC
LANGUAGE SQL
BEGIN
declare vSQL varchar(1024);
set vSQL = 'refresh table MQT_TEST';
execute immediate vSQL;
END#

Resources