Pass parameter to spool file - oracle11g

Say I have a sql file which is executed from command prompt (SQL Plus), which is working fine.
sqlplus dbusername/dbpassword#DBInstance #sqlfilename.sql
Now I need to pass a parameter to this sql spool file and according to the value of parameter I should be able to determine the functionality in the sql file. In the below sql code, I need to store the value that I am passing as parameter and in the variable parameter_Value
SET SERVEROUTPUT ON
SET DEFINE OFF
SPOOL "Test.log"
var parameter_Value VARCHAR2(20);
BEGIN
IF(parameter_Value='A')
THEN
--do something
ELSE
--do something
END IF;
END;
/
SPOOL OFF;
SET DEFINE ON
SET SERVEROUTPUT OFF
Can anyone please help how to perform this task?
Thanks in advance!

Your usage of the word spoolfile is not correct. sqlfilename.sql is the sql file or sqlplus file. The output file Test.log is the spool file.
you call
sqlplus dbusername/dbpassword#DBInstance #sqlfilename.sql A
to call the following file
SPOOL "Test.log"
DEFINE MY_VALUE=&1
SET SERVEROUTPUT ON
var parameter_Value VARCHAR2(20);
EXEC :parameter_Value:='&MY_VALUE'
SET DEFINE OFF
BEGIN
IF(:parameter_Value='A')
THEN
--do something
ELSE
--do something
END IF;
END;
/
SET DEFINE ON
SET SERVEROUTPUT OFF
SPOOL OFF;
the substitution of the & variables is a simple text substitution. It can be turned off by executing SET DEFINE OFF. The substituion raises information messages by sqlplus that can be turned off by executing SET VERIFY OFF
you should start with the SPOOL command, you won't see errors thrown by commands executed before you start spooling into the logfile. This can make debugging tedious. Also you should execute all commands before SPOOL OFF
the parameters in the command line are referend by their position number. I prefer assigning them to a named variable and use the named variable later. This is not necessary. You can use the positional parameter later, too, instead of using a named parameter. But using named parameter makes it easier to change the file if the position of a parameter changes. Also it can document the purpose of the parameter if you choose an appropriate name. I didn't in this example.
You cannot disable the special property of the & character with SET DEFINE OFF before the parameter substitution. You have to postpone it until you have done all your substitutions. Otherwise the substitution will not work.
a bind variable is definded with the VAR ... statement in sqlplus. In an SQL text it must be referenced with a preceding colon (:).
EXEC statement is an abbreviation for BEGIN statement; END
be aware that the --do something is in a PL/SQL block. So it must be replaced by PL/SQL statements and not by SQL statements or SQL*Plus statements.
So it cannot be replaced by a CREATE TABLE ... statement (this is SQL but not PL/SQL) and it cannot be replaced by a SPOOL OFF statement, which is SQL*Plus but not PL/SQL.

Related

I am trying to save the result of show con_name to a variable in ORACLE PL/SQL SQLPLUS

I want to write something like this:
exec SHOW CON_NAME into :=connection_name
but this doesnt work.
I know I can do this but I want to know for future reference if there is any way to do this for show
EXEC SELECT SYS_CONTEXT('USERENV','CON_NAME') into :connection_name from DUAL;
exec is just a wrapper for an anonymous block, so
exec SHOW CON_NAME into :=connection_name
is the same as
begin SHOW CON_NAME into :=connection_name end
Even with other issues fixed, show is a SQL*Plus client command, and doesn't mean anything inside a SQL or PL/SQL context.
You could do:
exec :connection_name := SYS_CONTEXT('USERENV','CON_NAME');
to avoid the context switch of selecting from dual within the PL/SQL.
Looking at the statement log in SQL Developer, show con_name is doing something similar, with a checkone bind variable it uses internally; though it also puts it through a local PL/SQL variable and trims that to 30 chars.
You could also use column ... new_value ... and query from dual, without using PL/SQL, and then use a substitution variable to refer to the value later instead of a bind variable:
column con_name new_value connection_name
select SYS_CONTEXT('USERENV','CON_NAME') as con_name from dual;
-- then later...
select '&connection_name' from dual;
Not sure how useful that would be though. Depends what you want to use it for I suppose.

How to correctly make a procedure in Pl/SQL in which I create a TABLE and use a CURSOR

The assignment I am trying to do is
"Create a procedure that places the names of all presidents who were born in one specific
state, in a temporary table. Display the contents of this table."
The procedure complies but when I try to invoke it, it gives me:
00000 - "table or view does not exist"
Error(8,5): PLS-00103: Encountered the symbol "CREATE" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior
I have been stuck for a while now. Does anybody know what I am doing wrong?
My code so far is:
CREATE OR REPLACE PROCEDURE stateofpresident(p_state president.state_born%TYPE)
AS
CURSOR c_state IS
SELECT *
FROM president;
BEGIN
execute immediate 'CREATE TABLE presidentFromState;
(
president_name VARCHAR2
)';
FOR r_state IN c_state LOOP
IF(p_state = r_state.state_born) THEN
execute immediate 'INSERT INTO presidentFromState VALUES(r_state.pres_name)';
commit;
END IF;
END LOOP;
execute immediate 'DROP TABLE presidentFromState';
END stateofpresident;
/
SET SERVEROUT ON
BEGIN
stateofpresident('VIRGINIA');
END;
/
SELECT *
FROM presidentFromState;
The immediate cause of your error is the semi-colon (;) at "presidentFromState;" At run fhat terminates the statement and the SQL interpreter at that point does not know what is want, the create syntax is invalid. The statement compiles because at compile time it is a properly formatted string. That is why dynamic SQL should be avoid if at all possible. Your script also has an additional error. Your last select will fail as the table presidentFromState ws not only created but also dropped in the procedure. Finally, just an FYI, the entire FOR cursor and the cursor itself is entirely unnecessary, the entire operation can be completed is one statement: Look into the structure
Insert into table_name(columns)
Select columns ...
Since this obviously an assignment or tutorial I'll leave the exact for your research.

bind variable substitution in oracle

The below simple procedure is suppose to provide grants to the user scott in oracle.
The value for &scott_SCHEMA is already defined in a seperate file(define_variable.sql) and the value is getting substituted correctly, but im getting the error(as specified in the bottom of the script), a help is much appreciated.
SET SERVEROUTPUT ON
declare
l_sql varchar2(3200);
begin
for i in ( select table_name as oname,'TABLE' as type from all_tables where owner='HR' AND table_name not like 'BIN$%' union all select view_name as oname,'VIEW' as type from all_views where owner='HR' and view_name not like 'BIN$%' )
loop
if i.type = 'TABLE' then
dbms_output.put_line(l_sql);
l_sql:= 'grant select,insert,update,delete on hr.'||i.oname||' to :owner with grant option';
execute immediate l_sql using '&scott_SCHEMA';
else
l_sql:= 'grant select on hr.'||i.oname||' to :owner with grant option';
end if;
end loop;
end;
/
*declare
*
ERROR at line 1:
ORA-00987: missing or invalid username(s)
ORA-06512: at line 12*
You can't use bind variables in place of identifiers (specifically schema or object names) in DDL or DML statements, they can only be used in place of value expressions.
Since you're using substitution variables, you could just place it in the sql statement itself:
l_sql:= 'grant select,insert,update,delete on hr.'||i.oname||' to &scott_SCHEMA with grant option';
and execute it with out passing it as a parameter:
execute immediate l_sql;
On a side note, your DBMS_OUTPUT line should come after you assignment to l_sql, otherwise you'll miss outputting one or more of the statements being processed. A good place would be between the assignment statement and the execute statement.

how do you spool from a stored procedure that is executed through a database link?

I am using a UNIX script to run sql code that kicks off a stored procedure via database link. I can get the procedure to complete successfully, however none of the DBMS outputs are spooled to the SPOOL file indicated.
SQL within UNIX:
set feedback off;
set linesize 500;
set serveroutput on size 1000000;
set serveroutput on format wrapped;
spool $SQLspool;
whenever oserror exit;
whenever sqlerror exit sql.sqlcode;
DECLARE
retcode integer :=0;
BEGIN
owner.procedure#db;
dbms_output.put_line('');
dbms_output.put_line('return code: ' || retcode);
dbms_output.put_line('');
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
/
EXIT;
SPOOLFILE CONTENTS:
return code: 0
I list a bunch of DMBS outputs within the stored procedure but nothing is written to the spool file.
How can I get it to output to the spool file?
I tried to have IN OUT variables, but because the procedure contains COMMITs it errors out with the parameters since it is going through the DB Link...
The output for PUT and PUT_LINE is buffered. From the Oracle docs
:
SQL*Plus does not display DBMS_OUTPUT messages until the PL/SQL program completes. There is no mechanism for flushing the DBMS_OUTPUT buffers within the PL/SQL program.
So, if you are looking to stream responses you are going to need to write a small program which does not buffer the output.

Easiest method to test an Oracle Stored Procedure

I'm working on an ASP.NET project with an Oracle Database. We are using TOAD to add/manage the stored procedures -- and in general I like TOAD and Oracle. The one thing I've found frustrating is finding a simple way to test an Oracle Stored Proc, such as SQL Server's "exec [SP_NAME] Param1, Param2, ParamN" syntax.
All of our stored procedures output Ref Cursors. Here is an example of a Stored Proc:
CREATE OR REPLACE PROCEDURE APP_DB1.GET_JOB
(
p_JOB_ID IN JOB.JOB_ID%type,
outCursor OUT MYGEN.sqlcur
)
IS
BEGIN
OPEN outCursor FOR
SELECT *
FROM JOB
WHERE JOB_ID = p_JOB_ID;
END GET_JOB;
/
Any suggestions?
You just need a script that calls your stored procedure and has a bind variable for the ref cursor output to display it in TOAD's grid in the Editor window.
DECLARE
type result_set is ref cursor;
BEGIN
APP_DB1.GET_JOB(1, :result_set);
END;
When you then run this TOAD will prompt you to 'bind' :result_set, just select ref cursor from the list of types and then the result will display in the grid. The trick is to think of yourself as a 'client' calling your stored procedure and you need your own ref cursor to store the result.
If you just looking for a way to invoke the SP, then the Oracle way is:
begin
sp_name(....);
end;
I don't use Toad, but you should be able to put this into a SQL window and execute it.
In sqplus you can use the syntax
SQL>var rc refcursor
SQL>exec APP_DB1.GET_JOB(the job id you want to query, :rc)
SQL>print rc
That should do it. The first line defines a bind variable. You could also define a variable for the job id, or just type it in.
TOAD shows the result in a grid just fine with sample script from Russel. Run as script.
variable P_CUR refcursor;
exec PACK.GETEXECUTION ( '9f363e49-88c1-4295-b61e-60812d620d7e', '6', :P_CUR );
print P_CUR;
Thanks!
The idea is just to bind the outCursor variable to a cursor when toad prompts you for the variable type. Just pass the other variables the usual way. Like in the example below.
BEGIN
APP_DB1.GET_JOB(1, :v_outCursor);
END;
Run it and a dialogue box will prompt you to bind the :outCursor variable as shown in the following image.
Toad will then display the result in the result grid.

Resources