I am writing this below stored procedure but i am also getting the exception while compiling the procedure in oracle, below is the procedure
CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS
PROCEDURE TEST_TABLE
--This procedure will delete partitions for the following tables:
--TEST_TABLE
BEGIN
FOR cc IN
(
SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_TABLE'
)
LOOP
EXECUTE IMMEDIATE 'BEGIN
IF sysdate >= ADD_MONTHS(' || cc.high_value || ', 3) THEN
EXECUTE IMMEDIATE
''ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name || '
'';
END IF;
dbms_output.put_line('drop partition completed');
END;';
END LOOP;
exception
when others then
dbms_output.put_line(SQLERRM);
END;
END;
/
and the exception that I am getting it while compiling is Please advise how to overcome from this.
Error(7,1): PLS-00103: Encountered the symbol "BEGIN" when expecting one of the following: ( ; is with authid as cluster order using external deterministic parallel_enable pipelined result_cache The symbol ";" was substituted for "BEGIN" to continue.
Error(22,25): PLS-00103: Encountered the symbol "DROP" when expecting one of the following: * & = - + ; < / > at in is mod remainder not rem return returning <an exponent (**)> <> or != or ~= >= <= <> and or like like2 like4 likec between into using || bulk member submultiset
You need to make correct quotation as below( and one more is keyword just after PROCEDURE TEST_TABLE "thanks to Alex who make me awaken" ) :
CREATE OR REPLACE PACKAGE BODY PKG_TEST_TABLE IS
PROCEDURE TEST_TABLE IS
--This procedure will delete partitions for the following tables:
--TEST_TABLE
BEGIN
FOR cc IN
(
SELECT partition_name, high_value
FROM user_tab_partitions
WHERE table_name = 'TEST_TABLE'
)
LOOP
BEGIN
IF sysdate >= ADD_MONTHS(cc.high_value, 3) THEN
EXECUTE IMMEDIATE
'ALTER TABLE TEST_TABLE DROP PARTITION ' || cc.partition_name;
Dbms_Output.Put_Line('Dropping partition is completed.');
END IF;
END;
END LOOP;
EXCEPTION WHEN Others THEN Dbms_Output.Put_Line( SQLERRM );
END TEST_TABLE;
END PKG_TEST_TABLE;
/
As a little suggestion use a different name for package than procedure such as PKG_TEST_TABLE against confusion.
Edit : of course you need to create a specification part for a package before the body part of the package :
CREATE OR REPLACE PACKAGE PKG_TEST_TABLE IS
PROCEDURE TEST_TABLE;
END PKG_TEST_TABLE;
/
The first error message tells you something is missing before BEGIN, and even mentions the two possible options in the 'when expecting' list. You need to change it to:
PROCEDURE TEST_TABLE IS
-- ^^
Or you can use AS instead of IS if you prefer...
The second error is because you have a string literal embedded in your dynamic SQL and you haven't escaped the single quotes, though you have elsewhere:
...
dbms_output.put_line(''drop partition completed'');
-- ^ ^
END;';
You could use the alternative quoting mechanism instead.
I'm not sure why you're doing two levels of dynamic SQL; you can do the dbms_output() and evaluate cc.high_value statically, and decide whether to make the alter call, with only that part dynamic (as #BarbarosÖzhan has shown, so I wont repeat that!). Or do the high-value check within the cursor query.
I am still getting exception Error(1,14): PLS-00304: cannot compile body of 'TEST_TABLE' without its specification
If you want a package then you have to create its specification before you try to create its body:
CREATE OR REPLACE PACKAGE TEST_TABLE AS
PROCEDURE TEST_TABLE;
END TEST_TABLE;
/
CREATE OR REPLACE PACKAGE BODY TEST_TABLE AS
PROCEDURE TEST_TABLE IS
BEGIN
FOR cc IN
...
LOOP
...
END LOOP;
END TEST_TABLE; -- end of procedure
END TEST_TABLE; -- end of package
/
Having the package name the same as a procedure within it is a bit odd and confusing.
But maybe you didn't actually want a package at all, and were trying to create a standalone procedure, in which case just remove the package-body part:
CREATE OR REPLACE PROCEDURE TEST_TABLE AS
BEGIN
FOR cc IN
...
LOOP
...
END LOOP;
END TEST_TABLE; -- end of procedure
/
Read more.
I would strongly suggest you get rid of the exception handler, and I've left that out of those outlines - you should let any exception flow back to the caller. You don't know that whoever calls this will even have output enabled, so might well not even see the message you're printing instead. Only ever catch exceptions you can handle and need to handle at that point.
Related
I have a big Oracle script with thousands of package call inside a BEGIN - END;
Is there a way to ignore the lines that causes error and continue executing the next lines? Some sort of "On Error Resume Next" in vb.
If you have only one BEGIN END section, then you can use EXCEPTION WHEN OTHERS THEN NULL.
SQL> declare
v_var pls_integer;
begin
select 1 into v_var from dual;
-- now error
select 'A' into v_var from dual;
exception when others then null;
end;
SQL> /
PL/SQL procedure successfully completed.
SQL> declare
v_var pls_integer;
begin
select 1 into v_var from dual;
-- now error
select 'A' into v_var from dual;
--exception when others then null;
end;
/
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 6
SQL>
The whole concept of "ignore errors" is a bug, and a lie if any errors occur. That is not to say you cannot trap errors and continue processing, just that you MUST handle the errors. For example, assume the use case: "Data has been loaded into a stage table from multiple .csv files. Now load into the tables A and Table B according to ....".
create procedure
Load_Tables_A_B_from_Stage(process_message out varchar2)
is
Begin
For rec in (select * from stage)
loop
begin
insert into table_a (col1, col2)
values (rec.col_a1, col_a2);
insert into table_b (col1, col2)
values (rec.col_b1, col_b2);
exception
when others then null;
end;
end loop;
process_message := 'Load Tables A,B Complete';
end ;
Now suppose a user created the a .csv file entered "n/a" in numeric columns where there was no value or the value was unknown. The result of this all too common occurrence is all such rows were not loaded, but you have no way to know that until the user complains their data was not loaded even though you told them it was. Further you have no way of determining the problem.
A much better approach is to "capture and report".
create procedure
Load_Tables_A_B_from_Stage(process_message out varchar2)
is
load_error_occurred boolean := False;
Begin
For rec in (select * from stage)
loop
begin
insert into table_a (col1, col2)
values (rec.col_a1, rec.col_a2);
exception
when others then
log_load_error('Load_Tables_A_B_from_Stage', stage_id, sqlerrm);
load_error_occurred := True;
end;
begin
insert into table_b (col1, col2)
values (rec.col_b1, rec.col_b2);
exception
when others then
log_load_error('Load_Tables_A_B_from_Stage', stage_id, sqlerrm);
load_error_occurred := True;
end;
end loop;
if load_error_occurred then
process_message := 'Load Tables A,B Complete: Error(s) Detected';
else
process_message := 'Load Tables A,B Complete: Successful No Error(s)';
end if;
end Load_Tables_A_B_from_Stage ;
Now you have informed the user of the actual status, and where you are contacted you can readily identify the issue.
User here is used in the most general sense. It could mean a calling routine instead of an individual. Point is you do not have to terminate your process due to errors but DO NOT ignore them.
I don't think there is any magic one-liner that will solve this.
As others have, use a editor to automate the wrapping of each call within a BEGIN-EXCEPTION-END block might be quicker/easier.
But, if feel a little adventurous, or try this strategy:
Let's assume you have this:
BEGIN
proc1;
proc2;
proc3;
.
.
.
proc1000;
END;
You could try this (untested, uncompiled but might give you an idea of what to try):
DECLARE
l_progress NUMBER := 0;
l_proc_no NUMBER := 0;
e_proc_err EXCEPTION;
-- A 'runner' procedure than manegrs the counters and runs/skips dpending on these vals
PROCEDURE run_proc ( pname IN VARCHAR2 ) IS
BEGIN
l_proc_no := l_proc_no + 1;
IF l_proc_no >= l_progress
THEN
-- log 'Running pname'
EXECUTE IMMEDIATE 'BEGIN ' || pname || '; END;' ;
l_progress := l_progress + 1;
ELSE
-- log 'Skipping pname'
END IF;
EXCEPTION
WHEN OTHERS THEN
-- log 'Error in pname'
l_progress := l_progress + 1;
RAISE e_proc_err;
END;
BEGIN
l_progress := 0;
<<start>>
l_proc_no := 0;
run_proc ( 'proc1' );
run_proc ( 'proc2' );
run_proc ( 'proc3' );
.
.
run_proc ( 'proc1000' );
EXCEPTION
WHEN e_proc_err THEN
GOTO start;
WHEN OTHERS THEN
RAISE;
END;
The idea here is to add a 'runner' procedure to execute each procedure dynamically and log the run, skip, error.
We maintain a global count of the current process number (l_proc_no) and overall count of steps executed (l_progress).
When an error occurs we log it, raise it and let it fall into the outer blocks EXCEPTION handler where it will restart via an (evil) GOTO.
The GOTO is placed such that the overall execution count is unchanged but the process number is reset to 0.
Now when the run_proc is called it sees that l_progress is greater than l_proc_no, and skips it.
Why is this better than simply wrapping a BEGIN EXCEPTION END around each call?
It might not be, but you make a smaller change to each line of code, and you standardise the logging around each call more neatly.
The danger is a potential infinite loop which is why I specify e_proc_err to denote errors within the called procedures. But it might need tweaking to make it robust.
Im a learning plsql and im trying to create procedure and calling procedure inside another procedure and i can get desired output. But when i tried to create procedure inside another procedure instead of calling another procedure, im getting the below error
"23/1 PLS-00103: Encountered the symbol "PROCEDURE" when expecting one of the following: ( begin case declare end exception exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge The symbol "declare" was substituted for "PROCEDURE" to continue.
23/18 PLS-00103: Encountered the symbol "." when expecting one of the following: in out ... long double ref char time timestamp interval date binary national character nchar
Errors: check compiler log
"
CREATE OR REPLACE PROCEDURE pro (
empn NUMBER,
emp OUT emp5%rowtype
) IS
salar number;
BEGIN
SELECT
a.*
INTO emp
FROM
emp5 a
WHERE
a.empno = empn;
dbms_output.put_line('The hire date is'
|| ' '
|| emp.hiredate);
dbms_output.put_line('Name is'
|| ' '
|| emp.ename);
procedure p44(emp.hiredate in date,emp.ename varchar,sal out number) IS
salar NUMBER;
BEGIN
SELECT
e.sal
INTO salar
FROM
emp5 e
WHERE
e.hiredate = hire
AND e.ename = enamee;
dbms_output.put_line('salary of the employee'
|| ' '
|| enamee
|| 'is '
|| salar);
END p43;
/
If i give empno number as input to procedure pro, i need output with employees hiredate,employee's name and employee's salary like the below one
The hire date is 20-FEB-81
Name is ALLEN
salary of the employee ALLEN is 1600
A procedure is a single program unit with the structure of:
create or replace procedure p43 () is
...
begin
…
end;
/
Your code has two instances of PROCEDURE and that's what the compiler is complaining about.
If you want two separate procedures you need two separate CREATE statements:
create or replace procedure p43 () is
...
begin
…
end p43;
/
create or replace procedure p44 () is
...
begin
…
end p44;
/
But if what you want is P44 as a private procedure only accessible within the context of P43 you can do that, by defining the procedure in the declaration section after any variable declarations:
create or replace procedure p43 () is
…
procedure p44 () is
...
begin
…
end p44;
begin
…
p44(…);
end p43;
/
Also this is not how we declare parameters.
procedure p44(emp.hiredate in date,emp.ename varchar,sal out number) IS
Give them unique names, say by prefixing them with p_, and if you like use the table column datatype. Something like this:
procedure p44(p_hiredate in emp.hiredate%type
,p_ename in emp.ename%type
,p_sal out emp.sal%type) IS
Giving parameters a distinct name prevents scope confusion when using parameters in SQL statements:
You can not create procedure within procedure.
Procedure is a single object and must be created alone. You can call one procedure from another.
You can use package to create multiple procedures inside single package but in that case also, procedure must be created standalone.
-- procedure must be created standalone
Create or replace procedure p44
As
Begin
-- code
End p44;
/
Create or replace procedure pro
As
Begin
P44; -- call to existing procedure
-- code
End pro;
/
So your case will go like this:
procedure p44(hiredate in date,ename varchar,sal out number) IS
salar NUMBER;
BEGIN
SELECT
e.sal
INTO salar
FROM
emp5 e
WHERE
e.hiredate = hire
AND e.ename = ename;
dbms_output.put_line('salary of the employee'
|| ' '
|| ename
|| 'is '
|| salar);
END p44;
/
CREATE OR REPLACE PROCEDURE pro (
empn NUMBER,
emp OUT emp5%rowtype
) IS
salar number;
BEGIN
SELECT
a.*
INTO emp
FROM
emp5 a
WHERE
a.empno = empn;
dbms_output.put_line('The hire date is'
|| ' '
|| emp.hiredate);
dbms_output.put_line('Name is'
|| ' '
|| emp.ename);
P44(emp.hiredate, emp.ename, salr):
END pro;
/
Cheers!!
I am trying to run the following stored procedure:
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL;
END;
END;
/
and calling it in changelog.xml as:
<sql>CALL RETRY_TRANS_EXCEPTION();</sql>
i get error:
Liquibase update Failed: Migration failed for change set eldata-changelog.xml::2016-08-25-cn-01::Ch Will:Reason: liquibase.exception.DatabaseException: Error executing SQL CALL RETRY_TRANS_EXCEPTION(): ORA-06575: Package or function RETRY_TRANS_EXCEPTION is in an invalid state
What i am trying to achieve is to be able to run a stored procedure through Liquibase with a loop in it.
Thanks for your help Prashant. What worked in my case was your solution plus one change:
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
v_query varchar2(100);
BEGIN
FOR i IN 1..500 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
v_query := 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NULL';
execute immediate v_query;
END loop;
END;
/
and then calling the Stored Procedure from the changelog, as:
<changeSet id="2016-08-25-cw-01" author="Ch Will">
<comment>
Testing retry logic on liquibase
</comment>
<sql>CALL RETRY_TRANS_EXCEPTION();</sql>
</changeSet>
You can't call it because the procedure does not compile correctly. Go back and fix the compilation errors, then try again.
Here are a couple of errors that stand out to me:
the for loop should end with end loop;, not end;
You can't have DDL statements directly in the code. You need dynamic SQL to execute a DDL statement from a procedure: execute immediate 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL';
Additional note: I don't understand why you are trying to execute the same DDL statement multiple times inside a loop. Obviously, you won't be able to add the same column with the same name over and over. You will get a runtime error.
SQL> CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
2 AS
3 BEGIN
4 FOR i IN 1..5 LOOP
5 DBMS_OUTPUT.PUT('Try #' || i);
6 ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL;
7 END;
8 END;
9 /
Warning: Procedure created with compilation errors
SQL> show err
Errors for PROCEDURE PRASHANT-MISHRA.RETRY_TRANS_EXCEPTION:
LINE/COL ERROR
-------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6/4 PLS-00103: Encountered the symbol "ALTER" when expecting one of the following: ( begin case declare end exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited-identifier> <a bind variable> << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Did required fixes :
CREATE OR REPLACE PROCEDURE RETRY_TRANS_EXCEPTION
AS
v_query varchar2(100);
BEGIN
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT('Try #' || i);
v_query := 'ALTER TABLE CIS_CASE ADD TEST01 varchar2(1) NOT NULL' ;
execute immediate v_query;
END loop;
END;
PLSQL stored procedure can't use DDL statements, like
alter table ...
so the
execute immediate ("...")
statement is required because in fact it creates an autonomous implicit transition that can't be rollbacked
I am working on some old PL/SQL code and I want to display the call hierarchy like I would have for Eclipse and Java code.
For instance, if I have the following code:
create or replace package body pkgA as
procedure foobar is begin
lambda(1);
end;
procedure lambda(a NUMBER) is begin
pkgB.test();
end;
end pkgA;
/
create or replace package body pkgB as
procedure test is begin
select 1 from dual;
end;
end pkgB;
/
I'd like to have this tree:
pkgB.test
pkgA.lambda
pkgA.foobar
Note: I am using Toad 9, but I did not see such feature (well, unless I need to look for to something like the referential tree for foreign keys).
Beside, I'm looking more for a static analysis than a dynamic, or something implying that I execute the code.
I think the better package procedure to call for this is: dbms_utility.format_error_backtrace
So you'd use DBMS_OUTPUT.PUT_LINE(dbms_utility.format_error_backtrace);
I put those in my exception handler for testing all the time (to the point where I have a code template that drops it in). I also output the instruction:
So it returns results like this:
EXCEPTION IN aeo_misc_tools.cursor_to_listV2 - -900: ORA-00900: invalid SQL statement
EXCEPTION IN my test script - -900: ORA-00900: invalid SQL statement
Error stack at top level:
ORA-06512: at "AEO.AEO_MISC_TOOLS", line 805
ORA-06512: at line 8
It won't format the error in a tree format, as you specified, but it gets the job done so you can find the error on the correct line.
You can use the called hierarchy of Visual-Expert, this tools analyse the PL code and show you the call function
It might not be the best solution, but I have figured out by using PL/Scope recursively. Hope it can help anyone in need. :)
create or replace procedure getAllChildCall ( definitionName in char, packageName in char, callLevel in number )
as
begin
for rec in (
with package_tree as (
select * from all_identifiers
where object_name = packageName and object_type = 'PACKAGE BODY'
)
select distinct
name, signature, type, line,
usage, usage_id, usage_context_id
from package_tree
start with (name = definitionName and usage = 'DEFINITION')
connect by prior usage_id = usage_context_id
) loop
if rec.usage = 'CALL' and rec.name not in (
'DEBUG', 'SQLERRM', 'COMMITRECORD', 'ISNOTZERO', 'NVL', 'TRUNC', 'ROUND') then
dbms_output.put_line(LPAD(' ', 2*callLevel, ' ') || rec.name);
getallchildcall(rec.name, packageName, callLevel+1);
end if;
end loop;
end;
/
set serveroutput on
declare
callLevel number;
begin
callLevel := 1;
dbms_output.put_line('start traverse the package child call graph...');
getAllChildCall(upper('YOUR_PROCEDURE_NAME'), upper('YOUR_PACKAGE_NAME'), callLevel);
end;
Is it possible to have conditional compilation in Oracle, where the condition is the existence of a database object (specifically, a table or view or synonym)? I'd like to be able to do something like this:
sp_some_procedure is
$IF /*check if A exists.*/ then
/* read from and write to A as well as other A-related non-DML stuff...*/
$ELSE /*A doesn't exist yet, so avoid compiler errors*/
dbms_output.put_line('Reminder: ask DBA to create A!')
$ENDIF
end;
Yes it is. Here a sample where the first stored procedure wants to select from XALL_TABLES, but if this table doesn't exist, select from dual. Finally, because I haven't got an XALL_TABLES object, the first stored procedure selects from dual. The second one, does the same thing on the ALL_TABLES object. Because the ALL_TABLES exists, the second stored procedure selects from all_tables but not from DUAL.
This kind of construction is useful where the package have to be deployed on all your database and use tables that are not deployed everywhere ... (ok, perhaps there is a conceptual problem, but it happens).
--conditionals compilation instructions accept only static condition (just with constants)
--passing sql bind variable doesn't work
--To pass a value to a conditional compilation instruction, I bypasses the use of input parameters of the script
--these 4 next lines affect a value to the first and the second input parameter of the script
--If your originally script use input script parameter, use the next free parameter ...
column param_1 new_value 1 noprint
select nvl(max(1), 0) param_1 from all_views where owner = 'SYS' and view_name = 'XALL_TABLES';
column param_2 new_value 2 noprint
select nvl(max(1), 0) param_2 from all_views where owner = 'SYS' and view_name = 'ALL_TABLES';
CREATE or replace PACKAGE my_pkg AS
function test_xall_tables return varchar2;
function test_all_tables return varchar2;
END my_pkg;
/
CREATE or replace PACKAGE BODY my_pkg AS
function test_xall_tables return varchar2 is
vch varchar2(50);
begin
$IF (&1 = 0) $THEN
select 'VIEW XALL_TABLES D''ONT EXISTS' into vch from dual;
$ELSE
select max('VIEW XALL_TABLES EXISTS') into vch from XALL_TABLES;
$END
return vch;
end test_xall_tables;
function test_all_tables return varchar2 is
vch varchar2(50);
begin
$IF (&2 = 0) $THEN
select 'VIEW ALL_TABLES D''ONT EXISTS' into vch from dual;
$ELSE
select max('VIEW ALL_TABLES EXISTS') into vch from ALL_TABLES;
$END
return vch;
end test_all_tables;
END my_pkg;
/
the test :
select my_pkg.test_xall_tables from dual;
give
VIEW XALL_TABLES D'ONT EXISTS
select my_pkg.test_all_tables from dual;
give
VIEW ALL_TABLES EXISTS
I would use 'EXECUTE IMMEDIATE' and a EXCEPTION clause.
Use dynamic SQL to create package constants to track which objects exist, and then use those constants in conditional compilation.
--E.g., say there are two possible tables, but only one of them exists.
--create table table1(a number);
create table table2(a number);
--Create a package with boolean constants to track the objects.
--(Another way to do this is to use ALTER SESSION SET PLSQL_CCFLAGS)
declare
table1_exists_string varchar2(10) := 'true';
table2_exists_string varchar2(10) := 'true';
temp number;
begin
begin
execute immediate 'select max(1) from table1 where rownum <= 1' into temp;
exception when others then
table1_exists_string := 'false';
end;
begin
execute immediate 'select max(1) from table2 where rownum <= 1' into temp;
exception when others then
table2_exists_string := 'false';
end;
execute immediate '
create or replace package objects is
table1_exists constant boolean := '||table1_exists_string||';
table2_exists constant boolean := '||table2_exists_string||';
end;
';
end;
/
--Look at the results in the source:
select * from user_source where name = 'OBJECTS';
--Create the object that refers to the tables.
create or replace function compile_test return varchar2 is
v_test number;
begin
$if objects.table1_exists $then
select max(1) into v_test from table1;
return 'table1 exists';
$elsif objects.table2_exists $then
select max(1) into v_test from table2;
return 'table 2 exists';
$else
return 'neither table exists';
$end
end;
/
--Check the dependencies - only TABLE2 is dependent.
select * from user_dependencies where name = 'COMPILE_TEST';
--Returns 'table 2 exists'.
select compile_test from dual;
Mixing dynamic SQL, dynamic PL/SQL, and conditional compilation is usually a very evil idea. But it will allow you to put all of your ugly dynamic SQL in one installation package, and maintain real dependency tracking.
This may work well in a semi-dynamic environment; for example a program that is installed with different sets of objects but does not frequently change between them.
(Also, if the whole point of this is just to replace scary error messages with friendly warnings, in my opinion that is a very bad idea. If your system is going to fail, the failure should be obvious so it can be immediately fixed. Most people ignore anything that starts with "Reminder...".)
No - that is not possible... but if you create a stored procedure referencing a non-existent DB object and try to compile it the compilation will show errors... the stored procedure will be there but "invalid"... and the compilation errors are accessible for the DBA whenever he looks at it... so I would just go ahead and create all needed stored procedures, if any compilation errors arise ask the DBA (sometimes the object exists but the stored procedure need permissions to access it...)... after the reason for the error(s) is fixed you can just recompile the stored procedure (via ALTER PROCEDURE MySchema.MyProcName COMPILE;) and all is fine...
IF you don't want code to be there you can just DROP the strored procedure and/or replace is via CREATE OR REPLACE... with dbms_output.put_line('Reminder: ask DBA to create A!') in the body.
The only other alternative is as kevin points out EXECUTE IMMEDIATE with proper EXCEPTION handling...
What I would do is check the existence via all_objects, something like:
declare
l_check_sql varchar2(4000);
l_cnt number;
begin
l_check_sql := q'{
select count(1)
from all_objects
where object_name = 'MY_OBJ'
and owner = 'MY_OWNER'
}';
execute immediate l_check_sql into l_cnt;
if (l_cnt > 0) then
-- do something referring to MY_OBJ
else
-- don't refer to MY_OBJ
end if;
end;