spooling into a file the content of a variable - oracle

I have a variable defined like
variable my_var clob;
Then, in the pl/sql block I have another clob variable, x.
At the end of the block, I have
:my_var := x;
Then after the block, I start to spool into a file some ommands.
That "x" variable contains multiple select statements.
I have:
SPOOL .....
PROMPT SELECT .... from ....
PROMPT /
PROMPT :my_var
PROMPT /
But this doesn't work.
So I need in my final file to have a list of sql commands. The first is specified in clear with that PROMPT, but after I want to have all the SELECT statements in the file, which are contained in the variable :my_Var.
How can I spool the content of :my_Var into the file?
Thanks!

Related

Oracle case running all prompts

I've made this program and I was wondering why oracle prompts for input even when it does not run the 'D' case (when 'A' is imputed for example).
SET SERVEROUTPUT ON;
ACCEPT p_user_letter PROMPT 'Enter an option';
DECLARE
v_user_letter VARCHAR2(200) := UPPER('&p_user_letter');
BEGIN
CASE v_user_letter
when 'A' then dbms_output.put_line('A pressed');
when 'D' then new_customer('&userEntered');
else dbms_output.put_line('Other');
END CASE;
END;
/
CREATE OR REPLACE PROCEDURE new_customer
(ccName IN Varchar2)
IS
BEGIN
dbms_output.put_line('Ran procedure');
END new_customer;
From the error message it seems like it runs a new and old version of declare which forces all uninitialized prompts to have a value, but i'm not certain and could not find out why online.
Both new and old running
('&userEntered'); is a substitution variable.
The substitution variables are not a part of SQL, this is a feature of SQL-Plus client, it is also supported by SQL-Developer.
When you hit Enter (or Run icon in SQL-Developer), SQL-Plus first analyses your script. When it finds &xxx string in your script, then prompts the user for a value. When the user enters the value then SQL-Plus substitutes (replaces) &xxx with the value entered by the user.
When SQL-Plus substitutes all substitution variables, then it starts to execute this script - that is, it sends SQL commands from the script to the Oracle Database for execution.
You can think of the variable substitution in SQL-Plus as a kind of macro preprocesing.

Using Variable- Oracle

In the above code, I am giving schemaname as input and using that input it should connect to the database. But In this case the value i entered is not taken by the schemaname. This is how the out put and the error is:
declare schemaname varchar2(20);
exec :schemaname := XYZ;
BEGIN
end;
Error report -
ORA-06550: line 2, column 6:
PLS-00103: Encountered the symbol "" when expecting one of the following:
constant exception <an identifier>
<a double-quoted delimited-identifier> table long double ref
char time timestamp interval date binary national character
nchar
ORA-06550: line 4, column 1:
PLS-00103: Encountered the symbol "CONNECT" when expecting one of the following:
Could any one suggest how to make it work using spool
the code between declare and end is PL/SQL. Commands like CONNECT or SPOOL are SQL*Plus commands. You cannot use SQL*Plus commands in a PL/SQL block.
In your case you don't need PL/SQL at all:
Create a script with following content
connect &1
spool C:\ABC
#c:\ABC
spool off;
and run it
#your_script_name
BTW: there is no reason to run script c:\ABC while you are spooling into it. What exactly do you want to achieve?
exec[ute] is SQL*Plus and SQL Developer (and maybe other clients) shorthand for an anonymous block. It is a client command, it is not part of PL/SQL. You are trying to use it inside a PL/SQL declare section, where it is not valid or recognised.
If you want a client bind variable you need the var[iable] command:
var schemaname varchar2(20);
exec :schemaname := '&1';
BEGIN
...
Notice the single quotes around &1, as it's being assigned to a string variable.
But you can't connect inside a PL/SQL block either, and you can't use a bind variable for the connection.
connect :schemaname
will prompt for a password (even if you defined it's value as user/passwd) and try to connect as a user lieterally called :schemaname.
You can use a substituion variable, but you don't really need to define a new one; as you seem to be passing the credentials in, you can do:
connect &1
(without surrounding quotes)

How to execute a oracle procedure having out parameter inside a unix script

Can any one please tell me how to execute a simple oracle stored procedure having out parameter inside a shell script.That means it should return a value into the unix environment.
I assume you want to start a script using SQLPLUS. This answer explains how to assign the value of an out parameter to a bind variable in SQLPLUS.
Call stored procedure from sqlplus
You can exit sqlplus with this value and use that value in the calling script.
exit x
But this usually is restricted to numerical values in a limited range.
There are a number of ways, but the one I tend to use is illustrated below.
The sqlplus script the_sql_script.sql
var ret varchar2(2000)
exec the_procedure ( the_out_param => :ret );
set pages 0 head off lines 200 trimspool on
spool sqlplus.return
select 'RETURN_VALUE=' || :ret FROM dual;
spool off
quit
In shell:
sqlplus / # the_sql_script.sql
. ./sqlplus.return
echo $RETURN_VALUE

how to write a batch file, which runs a PL/SQL block, to tell me many records are inserted/deleted/etc. in a log file?

I have created two batch files to run two separate .sql file in Windows Task Scheduler. The batch file for both looks like this:
sqlplus userid/password#database #C:\XXX.sql>>C:\output.log
echo commit; | userid/password#database
The first .sql file (SQL1) is a PL/SQL block like this:
SET SERVEROUT ON
DECLARE
....
BEGIN
IF ...
....
ELSE
#D:\DM_FIX.sql;
END IF
END
The DM_FIX.sql file is to insert a bunch of records into a table, and it starts with the INSERT command.
The second.sql file is not a block file. It's doing a bunch of DDL/DML comand. the file looks like below:
Truncate Table YYY
Reuse Storage;
Commit;
Insert into Table YYY
Select ... from
Commit;
Delete from Table YYY
where ...
Commit;
When I run the second .sql file, I get an output that indicates "The table has been truncated; #### records are inserted; #### records are deleted..."
But when I run the first, although the PL/SQL procedure is executed successfully, I don't get a line saying how many records are inserted, and I'm trying to figure out a way to do it.
Does any one know what could be the trick?
Thanks!
Revised Answer
As #Alex Poole helpfully pointed out, you can use the # nomenclature in a PL/SQL block from SQL*Plus, as that would load the second file's commands into the block that you're calling it from.
The reason that you're not getting any output is that, as far as SQL*Plus is concerned it's all one command: the SQLPlus block. In order to get output to your log for those commands, you'll need to create it yourself, using DBMS_OUTPUT. You would need to include a line like the one below after each command.
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' rows inserted');
However, you should note that doing this will cause your script to throw errors if it's ever called from outside of a PL/SQL block. My original solution would avoid this restriction, as it eliminates the need to use DBMS_OUTPUT.
Original Answer
I find it difficult to believe that the PL/SQL in the first file is executing successfully. This is because you're mixing SQL*Plus commands with PL/SQL code. They are separate systems - it's like trying to use shell commands natively in a programming language. You should be getting PLS-00103: Encountered the symbol "#" when expecting... from the first file.
SQL*Plus doesn't have conditionals, so, in order to keep the PL/SQL and SQLPlus commands seperate, you'd need to fake it somewhat. I'd suggest putting the file name into a substitution variable, then using that to run a file:
VARIABLE v_my_file_bind varchar2(100)
DECLARE
...
BEGIN
IF ...
...
:v_my_file_bind := 'D:\EMPTY_FILE.sql';
ELSE
:v_my_file_bind := 'D:\DM_FIX.sql';
END IF;
END;
/
COLUMN v_my_file_column new_value my_file_substitution noprint
SELECT :v_my_file_bind v_my_file_column from dual;
#&&my_file_substitution
To show count of modified rows in PL/SQL, use SQL%ROWCOUNT:
begin
insert into my_table ...
select ...
from ...;
dbms_output.put_line('Rows inserted: ' || SQL%ROWCOUNT);
commit;
end;
/
Remember, that SQL%ROWCOUNT variable will reset to 0 after commit.
Documentation: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/sql_cursor.htm

Can Sqlplus read the contents of a file into a variable?

I've been tinkering with sqlplus for awhile now, and I've managed to get sqlplus to read the contents of a file into a substitution variable as such:
exit | sqlplus -s login/pass#db #script.sql "`cat file.txt`"
This mostly works as my script requires... even newlines in the file are preserved. However, I was only using a sample file which was 50 or 60 bytes in size. The actual files I'll end up using will be at least a few kilobytes. So it was at this point I decided to check the max size of a substitution variable: 240 characters.
Is there a way within my sqlplus script to read a file's contents into a bind variable? The Oracle documentation seems to hint at this with the GET command, saying that typically you'll use this just to load a sql/sqlplus script.
http://docs.oracle.com/cd/B10501_01/server.920/a90842/ch13.htm#1009882
file_name[.ext] Represents the file you wish to load (typically a script).
Yes, there's a tricky way to do it.
Put something into props.txt and run the script:
DECLARE
-- the ## expression must be in separate line as follows
file_contents VARCHAR2(32767) := '
##props.txt
';
BEGIN
dbms_output.put_line('===');
dbms_output.put_line(file_contents);
dbms_output.put_line('===');
END;
/
Note that the file props.txt can not contain an "#" or you'll get nested
SQL*PLUS calls
No. Load would only store the file contents in Sql*Plus's own sql buffer. You can then run, edit and list the buffer.
A substitution variable is not the right place to load a file into. Use a bind variable of type clob for that and load the file contents using utl_file. But of course the file has to be located on the server in this case.
edit: if the data has to be located on the client, your option would be to load the clob using a pl/sql block and several calls to dbms_lob.writeappend
Your file would have to look like this (cannot test it ATM):
var l clob;
begin
dbms_lob.createtemporary(l);
dbms_lob.writeappend(l, 'abcdef...');
dbms_lob.writeappend(l, 'ijkl...');
end;
/
Please consider using literal quoted string - this allows you to have quotes in the linked file:
DECLARE
-- the ## expression must be in separate line as follows
file_contents VARCHAR2(32767) := q'[
##props.txt
]';
BEGIN
dbms_output.put_line('===');
dbms_output.put_line(file_contents);
dbms_output.put_line('===');
END;
/

Resources