Get a value from sql file to the invoking sql file - oracle

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.

Related

ORA-06561 while executing PL/SQL procedure

I have this procedure:
create or replace
PROCEDURE P_P2
IS
v_str varchar2(1000);
v_file_name varchar2(1000);
BEGIN
P_P1(v_str, 'EXPORT_CSV',v_file_name);
v_str := 'select * from H----)';
v_file_name := 'H_'||to_char(sysdate,'DD-MM-YYYY')||'.csv';
END;
I am getting error "ORA-06561: given statement is not supported by package DBMS_SQL" when I execute it:
Error starting at line : 165 in command -
exec P_P1
Error report -
ORA-06561: given statement is not supported by package DBMS_SQL
ORA-06512: at "SYS.DBMS_SQL", line 1120
ORA-06512: at "BIDB.P_P1", line 40
ORA-06512: at "BIDB.P_P2", line 7
ORA-06512: at line 1
06561. 00000 - "given statement is not supported by package DBMS_SQL"
*Cause: Attempting to parse an unsupported statement using procedure
PARSE provided by package DBMS_SQL.
*Action: Only statements which begin with SELECT, DELETE, INSERT, UPDATE,
LOCK, BEGIN, DECLARE or << (PL/SQL label delimiter) are supported.
I cannot see why. What am I doing wrong?
You haven't shown what P_P1 is doing, but from what you have shown, your P_P2 procedure may just be calling it too early; you have a call to P_P1 which uses v_str as a parameter, but it's null at that point - you set it after the call that uses it.
That means that somewhere in P_P1 you are probably ending up doing the equivalent of:
dbms_sql.parse(c, null, dbms_sql.native);
which throws the error you are seeing. You're doing the same with v_filename, which will presumably cause other issues.
So for a start, swap those lines around so the procedure is called last:
create or replace
PROCEDURE P_P2
IS
v_str varchar2(1000);
v_file_name varchar2(1000);
BEGIN
v_str := 'select * from H----)';
v_file_name := 'H_'||to_char(sysdate,'DD-MM-YYYY')||'.csv';
-- call this AFTER populating the variables
P_P1(v_str, 'EXPORT_CSV',v_file_name);
END;
/
You may have other problems of course - the table name looks odd, both because of the dashes and the closing parenthesis; but you may have just hidden the real name oddly. You seem to have changed the procedure names too (though inconsistently, as your exec seems to be calling the wrong one...).

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.

How to write an Oracle procedure with a select statement (Specifically on SQL Developer)?

I want to create a simple Oracle Stored procedure on SQL Developer that will return some records on a simple select query. I do not want to pass in any parameter, but I just want the Records to be returned back from the procedure into a result set -> a suitable variable.
I have been trying to use the following syntax :
create or replace PROCEDURE Getmarketdetails2(data OUT varchar2)
IS
BEGIN
SELECT *
into data
from dual;
END Getmarketdetails2;
But it gives me an error while I try to execute with the following exec statement -->
Declare a Varchar2;
exec Getmarketdetails2(a);
Error: PLS-00103: Encountered the symbol "end-of-file" when expecting "something else".
Cause: Usually a PL/SQL compilation error.
Appreciate if anyone can help me out of this long pending situation! I have tried enough to find a basic guide to create a simple Oracle stored procedure and execute it in SQL Developer, but none of them answer to the point!!
You want:
DECLARE
a VARCHAR2(4000); -- Give it a size
BEGIN -- Begin the anonymous PL/SQL block
Getmarketdetails2(a); -- Call the procedure
DBMS_OUTPUT.PUT_LINE( a ); -- Output the value
END; -- End the anonymous PL/SQL block
/ -- End the PL/SQL statement
or:
VARIABLE a VARCHAR2(4000); -- Create a bind variable
EXEC Getmarketdetails2(:a); -- Execute the procedure using the bind variable
PRINT a -- Print the bind variable
Assuming an up-to-date Oracle version, you can use dbms_sql.return_result()
create or replace PROCEDURE Getmarketdetails2
IS
c1 SYS_REFCURSOR;
BEGIN
OPEN c1 FOR
SELECT *
from dual;
DBMS_SQL.RETURN_RESULT(c1);
END Getmarketdetails2;
/
Then simply run
exec Getmarketdetails2
The only drawback is that SQL Developer only displays the result as text, not as a proper result grid.
This is how I return a cursor in Oracle
PROCEDURE GetAllData (P_CURSOR OUT SYS_REFCURSOR)
IS
BEGIN
OPEN P_CURSOR FOR
SELECT *
FROM TABLE ;
END GetAllData ;
Declare a Varchar2;
exec Getmarketdetails2(a);
Your procedure is ok;
Instead of above query, use below query to run sp:
Declare
a Varchar2(10);
Begin
Getmarketdetails2(a);
End;

Execution of Multiple procedures one after another is not working

I am trying to execute a procedure which in turn should execute four other procedures one after the other. How do I acheive this?
Create or replace procedure mainproc
as
begin
tack(400);
phno_insert;
address_insert;
academics_insert;
commit;
end;
Error report:
PLS-00905: Object phno_insert is invalid. PL/SQL: Statement ignored.
PLS-00905: Object address_insert is invalid. PL/SQL: Statement
ignored. PLS-00905: Object academics_insert is invalid. PL/SQL:
Statement ignored.
The problem seems to be in the fact that you have a procedure doing a DDL over an object that is statically referenced in another procedure; for example, if I define:
create table runtimeTable as select 1 as one from dual;
create or replace procedure createTable is
begin
execute immediate 'drop table runtimeTable';
execute immediate 'create table runtimeTable as select 1 as one from dual';
end;
create or replace procedure useTable is
vVar number;
begin
select one
into vVar
from runtimeTable;
--
dbms_output.put_line(vVar);
end;
create or replace procedure createAndUseTable is
begin
createTable;
useTable;
end;
/
when I try to execute createAndUseTable I get:
ORA-04068: existing state of packages has been discarded ORA-04065:
not executed, altered or dropped stored procedure "ALEK.USETABLE"
ORA-06508: PL/SQL: could not find program unit being called:
"ALEK.USETABLE" ORA-06512: at "ALEK.CREATEANDUSETABLE", line 4
ORA-06512: at line 1
If you strictly need to do a DDL runtime, you need to use dynamic SQL to reference the modified object; for example if I define the procedure useTable this way
create or replace procedure useTable is
vVar number;
begin
execute immediate
'select one
from runtimeTable'
into vVar;
--
dbms_output.put_line(vVar);
end;
the call to createAndUseTable will work:
SQL> exec createAndUseTable
1

Dynamic Query Error in PLSQL

I am trying to execute this procedure:
CREATE OR REPLACE PROCEDURE SP_DYNAMIC
AS
tbl_list VARCHAR2(2000);
DBLINK VARCHAR2(100);
V_SQL VARCHAR2(1000);
BEGIN
DBLINK := 'SOME_LINK';
V_SQL := 'SELECT table_name,table_owner FROM dba_tab_modifications#:DB_LINK';
EXECUTE IMMEDIATE V_SQL USING DBLINK;
COMMIT;
Dbms_Output.PUT_LINE (TBL_LIST);
END;
But When I execute the stored procedure I get the error:
ORA-01729: database link name expected
ORA-06512: at "SYSTEM.SP_DYNAMIC"
ORA-06512: at line 2
Can somebody help me with what I am doing wrong here?
The reason it doesn't work is because you can't use a bind variable as the dblink. You get the same error when running the following:
select * from dual#:dblink;
If you absolutely must use dynamic sql, you'd have to concatenate the dblink name into the statement - but you'll have to be aware that you're now open to SQL Injection:
V_SQL := 'SELECT table_name,table_owner FROM dba_tab_modifications#'||DB_LINK;

Resources