Oracle SQL script to build SQL script using dbms_output - oracle

This may be a stupid idea. I am trying to write a SQL*Plus .sql script that I can call from a Windows batch file that itself generates a new .sql script using dbms_output.put_line. This is what I have so far for my script:
set echo off;
set serverout on;
conn user#pass;
spool E:\new_script.sql
DECLARE
CURSOR c_groups IS
SELECT * FROM table;
s varchar2(4000);
BEGIN
dbms_output.put_line('BEGIN');
FOR x IN c_groups LOOP
s := 'INSERT INTO TABLE blah VALUES ('''||x.name||''','||x.id||');';
END LOOP;
dbms_output.put_line(s);
dbms_output.put_line('COMMIT;');
dbms_output.put_line('END;');
dbms_output.put_line('/');
END;
/
spool off;
exit;
However, when I do this, my new_script.sql just says "PL/SQL procedure successfully completed." Any ideas how to make the dbms_out.put_line actually display their message?
And I'm not actually doing this to build insert statements - those are just a simple sample showing the gist of what I'm trying to do.

You have to connect first and then use SET command. So your three commands should be in
this order:
conn user#pass;
set echo off;
set serverout on;
Otherwise, serveroutput parameter will be set to its default
value, which is OFF and that the reason why dbms_output.put_line()
hasn't been working as expected.
You should execute dbms_output.put_line(s) inside the FOR loop:
FOR x IN c_groups LOOP
s := 'INSERT INTO TABLE blah VALUES ('''||x.name||''','||x.id||');';
dbms_output.put_line(s);
END LOOP;
Moreover it's redundant to spool BEGIN .. END block. The DML statements
(bunch of INSERT INTO statements in this case) terminated by semicolon will be
executed just fine without being included in the BEGIN END block.
As you run your script using *.bat file, It probably will be useful to use the
following commands:
set feedback off; -- To not spool messages like
-- PL/SQL procedure successfully completed
set termout off; -- to suppress the output from a command line.
Your approach could probably be boiled down to a simple SELECT statement:
conn user#pass;
set echo off;
set serverout on;
set feedback off;
set termout off;
set heading off;
spool E:\new_script.sql
SELECT 'INSERT INTO TABLE blah VALUES ('''||name||'''','||to_char(id)||');'
FROM table;
spool off;
exit;

SPOOL sends the results to a file; but it doesn't ensure that results are printed. To enable the printing to stdout; use the SERVEROUTPUT command.
set serveroutput on
This is generally a poor way of going about things; I recognise that you said this wasn't what you're actually doing but SQL is a set based language. Do things in bulk if at all possible.

Related

Remove/Prevent First Blank from Oracle CSV MARKUP output file

I am currently writing scripts to output table data to CSV files so that they can be ingested into another platform. I'd much rather use the set markup CSV on quote on; SQL option to generate my output file. as it makes the script much cleaner and a whole lot simpler to write.
The problem, however, is that no matter how hard I try, I cannot seem to find an option that will prevent the output file from starting with a blank line. I need the column headers in the very first line and not in the second line.
The scripts need to run on a Windows Server against an Oracle 12c (12.1.0.2.0) Database, using SQLPLUS to execute the SQL commands and PowerShell/batch as the scripting wrapper.
After searching for some time and trying various options that only seem to have any effect on older approaches to CSV outputs. Eventually, I found the Oracle documentation for the SET command and discovered that things like SET NEWPAGE, SET TRIMSPOOL have no effect when using SET MARK[UP].
Oracle SET Command documentation is here: https://docs.oracle.com/en/database/oracle/oracle-database/12.2/sqpug/SET-system-variable-summary.html#GUID-0AA910C4-C22A-4A9E-BE13-AAA059CC7919
Is there a simple way to get rid of or suppress the first line that is blank? I really don't want to have to write further file processing scripts that go and remove the line from the file using PowerShell/Batch. That just seems like a really dumb thing to have to do...
A simplified version of my SQL is below and the output still includes the blank first line.
column thespoolfile new_value thespoolfile
select 'D:\Temp\outfile-detail-' || TO_CHAR( sysdate, 'YYYYMMDDHH24MI' ) || '.csv' as thespoolfile from dual;
set markup csv on quote on;
SET FEEDBACK OFF;
set trimspool on;
SET HEADSEP off;
SET SQLBLANKLINES off;
SET termout OFF;
spool &thespoolfile;
set define off;
select *
from <table>;
spool off;
exit
You need to use the following option
SET NEWPAGE NONE
It will suppress the first blank line, which is bothering you.
Cheers!!

remove blank lines from csv using shell script for oracle

Hi am using following shell script to create csv from oracle database
export ORACLE_HOME=/usr/lib/oracle/xe/app/oracle/product/10.2.0/server
export PATH=$PATH:$ORACLE_HOME/bin
sqlplus -s user1/user1<<!
Spool on
set heading off
SET FEEDBACK OFF
set wrap off
set colsep ,
SET LINESIZE 200
set trims on
Spool /home/ist/username.csv
select 'username','userid' from dual;
select username,userid from users;
Spool off
EXIT
!
I am getting following output
as you can see there is blank line at first and third row
but am expecting file without blank lines.
Any help will be appreciated.
Use the
SET PAGESIZE 0
command to avoid the blank lines. this also suppresses column headings, so you can remove
SET HEADING OFF
The command
SPOOL on
does not make sense because it starts spooling in a file named on.lst. So remove this command, too.
If you want to display the heading with the column name
you can try the following settings
set HEADING ON
SET FEEDBACK OFF
set WRAP OFF
set COLSEP ,
SET LINESIZE 32767
set NEWPAGE none
set UNDERLINE OFF
set TRIMSPOOL ON
set TRIMOUT ON
set PAGESIZE 50000
´heading on´ is the default so you must not set it. It enables the display of the column names when a select starts. underline off suppresses the '---' line between column names and data of a select. pages 50000 sets the pagesize to its maximum value (Oracle 11.2). linesize 32767 sets the linesize to its maximum value (Oracle 11.2). newpage none is necessary to suppress this empty line at the beginning of a page that was the primary concern of your posting.
All this can be found in the SQL*Plus Command Reference
The termout off parameter suppresses only output created by a scripts that is executed with the # or ## command. It dos not suppress out by a command entered in the SQL*plus console. If you use
sqlplus user/passw#connect <<!
...
!
you use the here-document syntax of the shell language which simulates the interactive input. So put your sql commands in a script, e.g. script.sql, and execute
sqlplus user/passw#connect #script.sql
then termout off will suppress terminal output.
Instead of
colsep ,
select username,userid
...
which returns something like
user1 , 14
nextuser , 236
myuser , 11
...
you can use leave the COLSEP unchanged and execute
select username||','||userid
...
to get the following output
user1,14
nextuser,236
myuser,11
...
Maybe this is useful
https://dba.stackexchange.com/a/64620/2047
set trimspool on
this will work for you
put this on your script
sed -i '/^\s*$/d'/home/ist/username.csv
Remove lines in /home/ist/username.csv without a , using
grep "," /home/ist/username.csv > /home/ist/username2.csv
# or
sed -i '/^[^,]*$/ d' /home/ist/username.csv
SQLPLUS 12.2 has an feature to output CSV, but you need to configure some settings to remove blank lines on it. Here is my approach
SET HEADING OFF;
SET PAGES 0;
SET SQLBLANKLINES ON;
set echo off;
set autotrace off;
set feedback off;
SET TRIM ON;
SET MARKUP CSV ON DELIMITER | QUOTE OFF;

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

SQLPLUS Command Skipped: set serveroutput on;

In ORACLE SQL Developer, this gets execute when am trying to run procedure call with its output.
create or replace
procedure allparam_proc(name varchar2,nestedtable_param VARCHAR2_TT)
is
begin
DBMS_OUTPUT.PUT_LINE('allparam_proc');
FOR i IN nestedtable_param.FIRST..nestedtable_param.LAST LOOP
DBMS_OUTPUT.PUT_LINE(nestedtable_param(i));
END LOOP;
end;
Problem :
set serveroutput on;
declare
fruits VARCHAR2_TT := VARCHAR2_TT('Orange','Kumquat','Grape','Banana');
begin
allparam_proc('leo',fruits);
end;
Output :
line 1: SQLPLUS Command Skipped: set serveroutput on;
In SQL Developer, Enabling serveroutput can be done via View -> Dbms Output
Using Semicolon is fine. But, Select what ever requires to be executed, and F5 (Execute as a Script) would be enough.
Good Practice, is to end every PL/SQL block with a / though the tool do it implicitly sometimes. Atleast it improves readability and continuity when the IDE has multiple anonymous PL/SQL blocks. Answers here have great explanations in detail.

How do I exit a script in SQLPlus when an error occurs and return to the SQLPlus prompt, without disconnecting or exiting SQLPlus?

I have some scripts that get run often, always from within a connected SQLPlus session.
I need a way to exit the script when an error occurs, without disconnecting or exiting SQLPlus itself. 100% of the time, when an error occurs, the connected DBA will need to issue one or more commands into the session. 100% of the time, when an error occurs, there are other SQLPlus statements (and thus must be outside of a BEGIN..END;) later on in the script that must not be executed or serious problems could arise.
NOTE: If you suggest WHENEVER SQLERROR EXIT then you didn't read the above text. That will disconnect and exit SQLPlus in addition to the script, which is not acceptable behavior.
I've found an interesting idea here which, when combined with spencer7593's answer, will get me selective sub-script calling, to which I can pass the PL/SQL output values. To wit:
VAR continue number;
EXEC :continue := 1;
BEGIN
SELECT some_bool_test() INTO :continue FROM dual;
END;
SET termout OFF
COLUMN script_name NEW_VALUE v_script_name
SELECT decode(:continue, 1, 'run_stuff.sql', 'skip.sql') script_name FROM dual;
SET termout ON
#&v_script_name :some_other_values
Where skip.sql is an empty text file.
UPDATE: I've moved most of this into a RUN.SQL file, where I pass in the boolean (0 or 1) as &1, the script name to call on success as &2, and then any other expected parameters to pass to the called script. Thus, it ends up looking something like this:
VAR continue number;
EXEC :continue := 1;
BEGIN
SELECT some_bool_test() INTO :continue FROM dual;
END;
#run.sql :continue 'run_stuff.sql' :some_other_values
It's not possible.
SQLPlus doesn't provide that level of control over the execution of a script.
Obviously, you'd need to AVOID using the WHENEVER SQLERROR EXIT ... command.
It's possible to gain conditional control over which SQL statements do or do not get executed as a result of raised exceptions (errors) using PL/SQL. But that doesn't address SQLPlus commands (which cannot be executed from within a PL/SQL block.)
DECLARE
lb_continue BOOLEAN;
BEGIN
lb_continue := TRUE;
BEGIN
sql statement
EXCEPTION
WHEN OTHERS THEN
lb_continue = FALSE;
END;
IF lb_continue THEN
BEGIN
sql statements
EXCEPTION
WHEN OTHERS THEN
lb_continue := FALSE;
END;
END;
Of course, that approach has it's own limitations and issues. Any DDL statements would need to be called dynamically; the easiest way to do that is an EXECUTE IMMEDIATE statement.
The biggest issue (in your case) is that it's not possible to execute SQLPlus commands from inside a PL/SQL block.
You can't exit the script and stay in SQL*Plus, but you can stop executing things. It isn't pretty, but assuming you can modify the script to add the control flow then you can just about do this with bind variable.
set serveroutput on
var flag char;
exec :flag := 'Y';
begin
if :flag != 'Y' then
raise program_error;
end if;
dbms_output.put_line('Doing some work');
/* Check for some error condition */
if 0 != 1 then
raise program_error;
end if;
/* Only reach this if earlier statements didn't fail
* but could wrap in another flag check if needed */
dbms_output.put_line('Doing some more work');
exception
when program_error then
dbms_output.put_line(sqlerrm);
:flag := 'N';
when others then
/* Real exception handling, obviously */
dbms_output.put_line(sqlerrm);
:flag := 'N';
end;
/
-- DML only does anything if flag stayed Y
select sysdate from dual
where :flag = 'Y';
-- Optional status message at the end of the script, for DBA info
set feedback off
set head off
select 'Something went wrong' from dual where :flag != 'Y';
set feedback on
set head on
When executed:
SQL> #script
PL/SQL procedure successfully completed.
Doing some work
ORA-06501: PL/SQL: program error
PL/SQL procedure successfully completed.
no rows selected
Something went wrong
SQL>
Any PL/SQL blocks in the script can check the flag status at the start, and raise program_error (just as a handy pre-defined exception) to jump back out. Anything that errors inside a PL/SQL block can update the bind variable flag, either directly or in an exception handler. And any non-PL/SQL DML can have an additional where clause to check the flag status, so if it's been set to N by the time that statement is reached, no work is done. (For an insert I guess that would mean not using the values form).
What this can't do is deal with any errors from plain SQL statements, but I'm not sure if that's an issue. If it is then those might need to be changed to dynamic SQL inside a PL/SQL block.
I know its old, but these two instructions at the very begining of the SQL script do the work:
WHENEVER SQLERROR EXIT FAILURE ROLLBACK
WHENEVER OSERROR EXIT FAILURE ROLLBACK

Resources