SQL*Plus does not run PL/SQL block - oracle

I have a problem running my PL/SQL script in SQL*Plus. I can run SQL commands normally but when I want to a run any PL/SQL code it gives nothing. See code and output below.
DECLARE
x_salary employee.salary%TYPE;
BEGIN
select salary
into x_salary
from employee
where ssn=&enter_ssn;
--Output the result
DBMS_OUTPUT.PUT_LINE('Salary is ' || x_salary);
EXCEPTION
--Output when no records are returned
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE ('No employee found');
WHEN others THEN
DBMS_OUTPUT.PUT_LINE ('Error encountered, but cause unknown');
END;

PL/SQL procedures needs / after procedure definition under sqlplus
DECLARE
...
BEGIN
...
END;
/

Put a slash / in a new line after END; in your script.
From the documentation:
You must include a semicolon at the end of each SQL command and a slash (/) on a line by itself after each PL/SQL block in the file.
Then execute the SQL file in SQL*Plus command line as:
#C:\your_script.sql;

Related

My script has first one invalid procedure and 2nd one valid procedure. I want the script to execute for at least 2nd valid object

I have below PLSQL Script where the PROC1 is invalid due to some reason(we are not discussing why) but PROC2 is valid.
Question: I want the script to run without any issue for at least PROC2? I want Valid PROC2 to be executed irrespective of invalid PROC 1.
BEGIN
PROC1; --This is due to x reason is invalid
PROC2;--This is valid.
END;
You can not execute any INVALID object in your PL/SQL block.
You can not even catch such exception in PL/SQL block. Oracle checks for the status of the all objects used in the pl/sql block and throws error if it is INVALID.
The best way to handle this is to change the proc1, recompile it so that it becomes VALID. That's it.
But, one way of doing it is using execute immediate as following:
declare
lv_status user_objects.status%type;
begin
select status into lv_status from user_objects where object_name = 'PROC1';
if lv_status = 'VALID' THEN
execute immediate 'call PROC1()';
END IF;
proc2;
end;
/
db<>fiddle demo
Cheers!!

Get a value from sql file to the invoking sql file

I have a file1.sql which invokes file2.sql.
file2.sql:
declare
v_stmt varchar2(1000);
begin
v_stmt := 'create index idx on tab1(&1)';
:stmt := v_stmt;
end;
/
file1.sql:
var stmt varchar2(4000);
#file2.sql 'col1'
:stmt;
Executing file1.sql throws the following errors:
SP2-0552: Bind variable "STMT" not declared.
SP2-0042: unknown command ":stmt" - rest of line ignored.
How do I get the value of variable v_stmt in file1.sql?
You can't run arbitrary code from the SQL*Plus command line using a bind variable; the bind variable is relevant to SQL and PL/SQL statements, not natively to SQL*Plus (even though it's declared there with the var).
To execute the statement you'll need to use dynamic SQL, in an anonymous PL/SQL block; so changing file1.sql to:
var stmt varchar2(4000);
#file2.sql 'col1'
begin
execute immediate :stmt;
end;
/
or slightly shorter, but also perhaps slightly confusing::
var stmt varchar2(4000);
#file2.sql 'col1'
exec execute immediate :stmt;
When I run that I see:
SQL> #file1
PL/SQL procedure successfully completed.
begin
*
ERROR at line 1:
ORA-00942: table or view does not exist
ORA-06512: at line 2
which is reasonable as I don't have your tab1 table in my schema. You can see that is trying to execute the statement though; and there is no SP2-0552 error (though I don't see that with your original code either).
You can also use print stmt to see the generated value before it's run (note there is no colon prefix); or you could use dbms_output within the anonymous block, of course.

how to dynamically purge the tables in AQADMIN

When I was trying to purge the QUEUE tables dynamically, I'm getting an error.Below is the code
set serveroutput on;
declare
l_stmt varchar2(2000):='';
po_t dbms_aqadm.aq$_purge_options_t;
BEGIN
for i in (select NAME,queue_table from all_Queues where owner='AQADMIN') loop
--dbms_output.put_line(i.queue_table);
l_stmt:='DBMS_AQADM.PURGE_QUEUE_TABLE ('''||i.queue_table||''',''trunc(enq_time)<sysdate-90'',block => po_t)';
execute immediate l_stmt;
--dbms_output.put_line(l_stmt);
commit;
end loop;
END;
/
Error message:
Error report -
ORA-00900: invalid SQL statement
ORA-06512: at line 8
00900. 00000 - "invalid SQL statement"
*Cause:
*Action:
To know if my query is framing correctly, I commented out the execute immediate part and uncommented the DBMS_OUTPUT command, and the result was posted in sql developer and it executed perfectly, (below is the code output) .so the query is correct, not sure what was wrong with my code,
Output:
anonymous block completed
DBMS_AQADM.PURGE_QUEUE_TABLE ('HEARTBEAT_MSG_QT','trunc(enq_time)<sysdate-90',block => po_t)
then I executed the above output in separate SQL block and it ran fine.Below
declare
po_t dbms_aqadm.aq$_purge_options_t;
begin
DBMS_AQADM.PURGE_QUEUE_TABLE ('HEARTBEAT_MSG_QT','trunc(enq_time)<sysdate-90',po_t);
end;
/
anonymous block completed
When you call execute immediate it is expecting dynamic SQL, not PL/SQL. To run a PL/SQL command you need to wrap it in an anonymous block, just as you did when you ran it manually:
l_stmt:='DECLARE po_t dbms_aqadm.aq$_purge_options_t; BEGIN DBMS_AQADM.PURGE_QUEUE_TABLE ('''||i.queue_table||''',''trunc(enq_time)<sysdate-90'',block => po_t); END;';
or split onto multiple line to make it slightly easier to read:
l_stmt:='DECLARE po_t dbms_aqadm.aq$_purge_options_t;'
|| 'BEGIN '
|| 'DBMS_AQADM.PURGE_QUEUE_TABLE ('''||i.queue_table||''','
|| '''trunc(enq_time)<sysdate-90'',block => po_t);'
|| 'END;';
Notice that you have to re-declare po_t inside that block as that the original declaration is out of scope for the dynamic SQL call (actually, the original one is now redundant...).
You don't need to use dynamic SQL though, you can pass the cursor value straight to the procedure:
DECLARE
l_po dbms_aqadm.aq$_purge_options_t;
BEGIN
for i in (select NAME,queue_table from all_Queues where owner='AQADMIN')
loop
DBMS_AQADM.PURGE_QUEUE_TABLE (queue_table => i.queue_table,
purge_condition => 'trunc(enq_time)<sysdate-90'
purge_options=> l_po);
end loop;
END;
/
I've also removed the commit as it's redundant; from the docs:
This procedure commits batches of messages in autonomous transactions.

Get input from user in PL/SQL procedure

I'm building a procedure which would require to get an input from user to print few details. But when I use & to get values it fails with errors. the logic is as follows..
DBMS_OUTPUT.PUT_LINE('Enter Y to display Unauthorized records OR N to skip the display');
--SELECT &1 INTO lv_choice FROM DUAL;
IF NOT ('&lv_choice'='Y') THEN
DBMS_OUTPUT.PUT_LINE ('RECORDS WILL NOT BE DISPLAYED');
ELSE
DBMS_OUTPUT.PUT_LINE ('RECORDS TO BE DISPLAYED ARE:');
......
I have tried using &1 into dual or directly calling &lv_choice which is failing with PLSQL internal errors.
Any methods to get input from user to proceed further in the procedure?
This isn't possible in PL/SQL - PL/SQL doesn't have access to the terminal(unless you do something like plug in Java or call your program from a something like SQL*Plus(in which you can use commands like ACCEPT/PROMPT before you run the procedure).
The & variables are substitution variables, and are specific to SQL*Plus, not PL/SQL
If you are using some UI Terminal like SQLDeveloper or TOAD, you can achieve it using below code:
CREATE OR REPLACE INPUTPROCEDURE (LV_CHOICE IN VARCHAR2)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE('Enter Y to display Unauthorized records OR N to skip the display');
--SELECT &1 INTO lv_choice FROM DUAL;
IF lv_choice <> 'Y' THEN
DBMS_OUTPUT.PUT_LINE ('RECORDS WILL NOT BE DISPLAYED');
ELSE
DBMS_OUTPUT.PUT_LINE ('RECORDS TO BE DISPLAYED ARE:');
END INPUTPROCEDURE;
And Invoke the above Procedure like below:
DECLARE
dyn_stmt VARCHAR2(200);
b BOOLEAN := TRUE;
BEGIN
dyn_stmt := 'BEGIN INPUTPROCEDURE(:LV_CHOICE); END;';
EXECUTE IMMEDIATE dyn_stmt USING b;
END;

Exit execution when error occurs PL/SQL

I would like to know, how can I exit the execution when an error occurs. In Microsoft SQL Server there is a RETURN clause, which does the work. But I would like to know similar functionality in Oracle. I am using Oracle Sql Developer. Here is the script I am using:
First block throws error due to Unique Key Violation, even though it throws error the execution goes to next block and executes the insert statement. I want to end the execution or exit at first block of code itself.
Please help me to write the code.
First anonymous PL/SQL block:
set serveroutput on;
BEGIN
insert into test values(1);
insert into test values(1);
COMMIT;
dbms_output.put_line('PRINT SOMETHING 1');
EXCEPTION
WHEN OTHERS THEN
if sqlcode <> 0
then
dbms_output.put_line(SQLCODE || ' ' || SQLERRM);
RAISE;
end if;
return;
END;
/
Second anonymous PL/SQL block:
set serveroutput on;
BEGIN
insert into test values(6);
COMMIT;
dbms_output.put_line('PRINT SOMETHING');
EXCEPTION
WHEN OTHERS THEN
if sqlcode <> 0
then
dbms_output.put_line(SQLCODE || ' ' || SQLERRM);
RAISE;
end if;
return;
END;
/
If you create a stored procedure, you have more control and can exit whenever you like with a return statement.
So create a stored proc:
create or replace procedure myProc as
begin
dbms_ouput.put_line('i am here');
return;
dbms_ouput.put_line('and not here');
end;
Then in sqlplus or developer:
exec myProc();
You can nest the blocks into a single 'program unit'.
In this way an exception in the first block will stop the whole program unit from executing, rather than just being limited in scope to the first block.
set serveroutput on;
BEGIN
BEGIN
insert into test values(1);
insert into test values(1);
COMMIT;
dbms_output.put_line('PRINT SOMETHING 1');
EXCEPTION
WHEN OTHERS THEN
if sqlcode <> 0
then
dbms_output.put_line(SQLCODE || ' ' || SQLERRM);
RAISE;
end if;
return;
END;
BEGIN
insert into test values(6);
COMMIT;
dbms_output.put_line('PRINT SOMETHING');
EXCEPTION
WHEN OTHERS THEN
if sqlcode <> 0
then
dbms_output.put_line(SQLCODE || ' ' || SQLERRM);
RAISE;
end if;
return;
END;
END;
/
You should be able to use "exit" - see the Oracle documentation here: http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12023.htm
Note that this will end your SqlPlus session, but I don't know of another way of doing it aside from using a single block or stored procedure.
Another useful statement is:
WHENEVER SQLERROR EXIT SQL.SQLCODE
Oracle documentation: http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch12052.htm
Thanks for your valuable comments.
JoshL, i tried using EXIT but i am ending up with error. Please correct my code( I am new to PL/SQL). "WHENEVER SQLERROR EXIT" is good to use but my issue is that I use these sql scriptsd in InstallShield, so InstallShield installers does not recognize these statements and throws error.
set serveroutput on;
BEGIN
insert into test values(1);
insert into test values(1);
COMMIT;
dbms_output.put_line('PRINT SOMETHING 1');
EXCEPTION
WHEN OTHERS THEN
if sqlcode <> 0
then
dbms_output.put_line(SQLCODE || ' ' || SQLERRM);
RAISE;
exit;
end if;
END;
/
The EXIT command is only for use within a loop in PL/SQL. The EXIT command leaves the loop at that point. If you use the EXIT command outside a loop in PL/SQL the compiler throws an error.
The EXIT command in SQLPlus exits the SQLPlus session.
This is confusing, because they are two different Oracle products. SQL*Plus can run PL/SQL and the EXIT statement is a valid statement in both products, but with different contexts.

Resources