Unable to geneate csv file from by executing .sql through shell - oracle

I am trying to generate a csv by calling a .sql file. The issue is on execution an empty file is being created. Running the sql against the DB returns records. Apologies if this has already been answered but I was not able to find any answer that fixed my issue.
FILE="CASE.csv"
export dest_loc=/dest/loc
export LOGFILE=$LOG/100.$NOW_TS.log
echo "$0 started at $(date +"%Y-%m-%d:%H:%M:%S")" > ${LOGFILE}
sqlplus -s $DB_LOGIN<<EOSQL>>${LOGFILE}
SET echo OFF
SET feedback OFF
SET sqlprompt ''
SET TERMOUT OFF
SET UNDERLINE OFF
SET trimspool ON
SET trimout ON
SET SQLBLANKLINES ON
SET PAGESIZE 50000
SET COLSEP "|"
SET LINESIZE 650
SPOOL $dest_loc/$FILE
#$SRC/sql_to_run.sql
SPOOL OFF
EOSQL
echo "\nChecking for ORACLE errors..." >> ${LOGFILE}
grep 'ORA-' $LOGFILE >> ${LOGFILE}
rc=$?
if [ ${rc} = 0 ];
then
echo "\nThere has been an ORACLE error. RC = $RC" >> ${LOGFILE}
echo "\n$0 ended at $(date +"%Y-%m-%d:%H:%M:%S")" >> ${LOGFILE}
echo "####################################" >> ${LOGFILE}
exit 2
else
echo "\nNo ORACLE errors found." >> ${LOGFILE}
fi
The log file captured
./100.sh started at 2021-10-20:20:14:22 Checking for ORACLE errors...
No ORACLE errors found.

The reason why the csv file is empty is probably because you have an error that you are not capturing. sqlplus is a binary program, so it will exit always with 0, unless you use whenever sqlerror and whenever oserror in order to capture exceptions produced in the execution, either because of a database error or a operating system issue.
Prior to 12c
FILE="CASE.csv"
export dest_loc=/dest/loc
export LOGFILE=$LOG/100.$NOW_TS.log
echo "$0 started at $(date +"%Y-%m-%d:%H:%M:%S")" > ${LOGFILE}
sqlplus -s $DB_LOGIN << EOSQL >> ${LOGFILE}
WHENEVER SQLERROR EXIT FAILURE;
WHENEVER OSERROR EXIT FAILURE;
SET echo OFF
SET feedback OFF
SET sqlprompt ''
SET TERMOUT OFF
SET UNDERLINE OFF
SET trimspool ON
SET trimout ON
SET SQLBLANKLINES ON
SET PAGESIZE 50000
SET COLSEP "|"
SET LINESIZE 650
SPOOL $dest_loc/$FILE
#$SRC/sql_to_run.sql
SPOOL OFF
EOSQL
rc=$?
if [ ${rc} -ne 0 ];
then
echo "\nThere has been an ORACLE error. RC = $RC" >> ${LOGFILE}
echo "\n$0 ended at $(date +"%Y-%m-%d:%H:%M:%S")" >> ${LOGFILE}
echo "####################################" >> ${LOGFILE}
exit 2
else
echo "\nNo ORACLE errors found." >> ${LOGFILE}
fi
12c or higher
If you are in this version, you might want to use the feature set markup csv to generate files.
FILE="CASE.csv"
export dest_loc=/dest/loc
export LOGFILE=$LOG/100.$NOW_TS.log
echo "$0 started at $(date +"%Y-%m-%d:%H:%M:%S")" > ${LOGFILE}
sqlplus -s $DB_LOGIN << EOSQL >> ${LOGFILE}
WHENEVER SQLERROR EXIT FAILURE;
WHENEVER OSERROR EXIT FAILURE;
SET echo OFF
SET feedback OFF
SET SQLBLANKLINES ON
SET PAGESIZE 50000
SET LINESIZE 650
SET TERMOUT OFF
SET MARKUP CSV ON DELIMITER "|"
SPOOL $dest_loc/$FILE
#$SRC/sql_to_run.sql
SPOOL OFF
EOSQL
rc=$?
if [ ${rc} -ne 0 ];
then
echo "\nThere has been an ORACLE error. RC = $RC" >> ${LOGFILE}
echo "\n$0 ended at $(date +"%Y-%m-%d:%H:%M:%S")" >> ${LOGFILE}
echo "##########################################" >> ${LOGFILE}
exit 2;
else
echo "\nNo ORACLE errors found." >> ${LOGFILE}
fi
Test Sqlplus Exit Status
$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Thu Oct 21 08:32:27 2021
Version 19.6.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.6.0.0.0
SQL> create table t1 ( c1 number );
create table t1 ( c1 number )
*
ERROR at line 1:
ORA-00955: name is already used by an existing object
SQL> exit
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.6.0.0.0
[ftpcpl#scglvdoracd0006 ~]$ echo $?
0
$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Thu Oct 21 08:32:43 2021
Version 19.6.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.6.0.0.0
SQL> whenever sqlerror exit failure;
SQL> create table t1 ( c1 number );
create table t1 ( c1 number )
*
ERROR at line 1:
ORA-00955: name is already used by an existing object
Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.6.0.0.0
$ echo $?
1

Related

Shell Script to trigger procedure with logging

Here is the shell script which need to trigger a stored procedure and when the record count is 0 then it should capture in the log that 0 duplicate records are found and if it's more than 0 then log with no of records.
Also if there is any sqlerror then it should write the same in the log file and it should send the communication in all scenarios.
We have funct file which has declared with all directories and we are referring here for the log file path directory.
Could you please help me to correct the code logic?
#!/bin/ksh
. /local/dir1/funct.sh
sqlplus -s ${ORAUSER}/${ORAPASSWD}#${ORASRVC} <<EOF > $LOG_TEXT
set head off
set serveroutput on
SELECT TO_CHAR(SYSDATE,'MMDDRRRRHH24MISS') FROM DUAL;
EOF
TIME_STAMP=`cat ${LOG_TEXT}`
LOG_FILE_NAME='FileStatus'${TIME_STAMP}'.log'
LOG_FILE=${LOGFILEDIR}'/FileStatus/'${LOG_FILE_NAME}
write_log "Database Timestamp is $TIME_STAMP"
write_log "Executing FileStatus now..."
sqlplus -s ${ORAUSER}/${ORAPASSWD}#${ORASRVC} <<EOF >> ${LOG_TEXT}
set feedback off
set heading off
DECLARE
v_count NUMBER;
BEGIN
select count(*) INTO v_count from (select col1,col2,count(col3) from Tab1 group by col1,col2 having count(col3)>1);
whenever sqlerror exit -1
whenever oserror exit -1
execute FileStatus;
END;
EOF
if [[ v_count -eq 0 ]] then
write_log "FileStatus executed successfully."
write_log "No Duplicate records Found: $LOG_FILE"
mailx -s "No Duplicate records Found" XXXXX#gmail.com < ${success}
elif [[ "$v_count -gt 0 ]]
then
write_log "FileStatus executed successfully."
write_log "Number of duplicate records found::$v_count:$LOG_FILE"
mailx -s "Number of duplicate records found:$v_count" XXXXX#gmail.com < ${success}
else
Write_log "FileStatus Failure."
mailx -s "FileStatus" XXXXX#gmail.com < ${failure}
fi
cleanup
exit 0;

Execute silent sqlplus in background from bash program

I want to know if its posible to execute in background a sqlplus like this
sqlplus -s "/ as sysdba" <<IN
select 1 from dual;
IN
I know that I can call a .sql file with nohup sqlplus ... #file.sql & but I want use the <
Something like this
nohup (sqlplus -s "/ as sysdba" <<IN
select 1 from dual;
IN) &
Or similar...
Regards,
You could do:
(
nohup sqlplus -s "/ as sysdba" <<IN
select 1 from dual;
IN
) &
You could do:
while [ 1 ]
do
sqlplus -s <<EOF
user/password#SID
WHENEVER SQLERROR EXIT SQL.SQLCODE
set feedback off
set serveroutput on
select 1 from dual;
EOF
sql_status=$?
if [ $sql_status -eq 0 ]
then
.
.
.
done

Why Sqlplus bash script NOT returning error for ORA-02291 integrity constraint when "WHENEVER SQLERROR EXIT 1" is used?

I have written a bash script to connect to sqlplus and execute all the sql scripts in a particular folder. Below is the execute method of the script.
execute() {
if [ ! -d "$DIR_SqlFiles" ]
then
echo "No sql files were found. Cannot find path ${DIR_SqlFiles}"
return 1
fi
echo "`date` :Connecting To ${userName}/******#${serviceName}";
for file in `ls ${DIR_SqlFiles}/*` ; do
echo "`date` :Executing file $file..."
echo "`date` :SQL OUTPUT:";
sqlplus -s ${userName}/${password}#${host}:${port}/${serviceName} <<EOF
WHENEVER OSERROR EXIT 1 ROLLBACK;
WHENEVER SQLERROR EXIT 1 ROLLBACK
#${file};
commit;
quit;
EOF
sql_return_code=$?
if [ ${sql_return_code} != 0 ]
then
echo "`date` ${file} failed"
echo "Error code ${sql_return_code}"
return 1;
fi
done
echo "`date` :completed running all sql scripts in the ${DIR_SqlFiles} folder."
return 0;
}
The problem is when one of the .sql files has ORA-02291: integrity constraint this script will not fail. Its returning 0 and it just prints "0 rows updated" without printing the actual error.
In other cases its working fine. For example, in case of wrong table name (ORA-00942: table or view does not exist) the script will fail and return 1.
Could anyone please point me to the right direction. Why for the first case errors its not failing?

Trap ORA errors in unix(HP-UX) shell script

Script:
while read -r records
do
sErrors=`sqlplus /<<EOF
WHENEVER SQLERROR EXIT SQL.SQLCODE;
select id from table where name='"$records"';
#if select succeeds then update
update table set name='xyz';
exit;
EOF`
if [[ $sErrors = "ORAsomenumber" ]]
then
echo "Failed for $records with error:$sErrors">>logfile.log
fi
done<file
I need to trap any error specific to select query(i.e. "NO DATA FOUND") or any
Database specific error that might occur for a record in a while loop and continue
without exit till the end of reading all records
Oracle version : 10.2.0.5.0
Note: it is not mandatory to get specific ORA error only, any hint indicating the specific db error would be enough
Thanks.
file:
name1 newname1
name2 newname2
name3 newname3
script:
#!/bin/sh
#set var
export ORACLE_HOME=/oracle/product/db_1/
export ORACLE_SID=orcl
export PATH=$ORACLE_HOME/bin:$PATH
ora_user="user"
ora_pwd="password"
ora_tns="dbtnsname"
log_file=/var/log/sql.log
while read user newname
do
sqlplus -S $ora_user/$ora_pwd#$ora_tns <<EOF >>$log_file
SET SERVEROUTPUT ON
DECLARE V_ID INT DEFAULT 0;
BEGIN
SELECT ID INTO V_ID FROM TABLE WHERE NAME = "$user";
IF V_ID = 0 OR V_ID IS NULL
THEN
DBMS_OUTPUT.PUT_LINE("FAILED FOR $user WITH ERROR:NOT DATA FOUND");
ELSE
UPDATE TABLE SET NAME="$newname" WHERE NAME = "$user";
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE("FAILED FOR $USER WITH ERROR:"||SQLERRM);
END;
/
EOF #must top grid
done<file
The way the sqlplus invoked is fine in your script, But string comparison does not work as it contains the whole error if you want to check for some particular error code (or) only some part of the string, Use grep command.
echo $sErrors | grep "ORA-ERROR1" && echo "ORA-ERROR1 Found"
echo $sErrors | grep "ORA-ERROR2" && echo "ORA-ERROR2 Found"
In the above case, it prints both grep output and the echo command output if it matches.
If you don't want the output to be printed, You can follow the below.
echo $sErrors | grep "ORA-ERROR1" > /dev/null 2>&1
if [ $? -eq 0 ];then
echo "ORA-ERROR1 Found"
fi

unix script - unable to trap or interpret error code within sqlplus properly

I am trying to run a shell script (ksh) that runs oracle sqlplus to run a sql script in the background. Within the sql script I am using WHENEVER SQLERROR EXIT SQL.SQLCODE to trap the error code so I can check it and exit my program, else continue to next sql statement.
I'm not sure if my problem is in my shell script trapping the error or the use of WHENEVER?
I am producing/invoking the ORA- error, but return code still shows as Return_code=0, (pass) and continues to run the next script. It should fail and exit the program.
Can someone help me configure this script properly? My if-then-else logic maybe flawed too. Thanks.
Here's my sql (whenever.sql) script to invoke error:
WHENEVER SQLERROR EXIT SQL.SQLCODE
begin
SELECT COLUMN_DOES_NOT_EXIST FROM DUAL;
END;
/
Here's my script:
KEY=$BASEDIR/.keyinfo;
LOG=$BASEDIR/run_tst.log;
# Check before we run
if [ -f "$KEY" ]
then
IFS="
"
set -A arr $(cat $KEY)
echo "Running Test ===>$TIMESTAMP" >> $LOG 2>&1
/bin/sqlplus ${arr[0]}/${arr[1]} #whenever.sql &
pid1=$!
echo "Waiting for PID:$pid1" >> $LOG 2>&1
wait $pid1
ret=$?
echo "Return_code=$?" >> $LOG 2>&1
if [ $ret !=0 ] #if not success
then
exit $ret
echo "Error found...Return_code=$?" >> $LOG 2>&1
echo "Error found...exiting program ===>$TIMESTAMP" >> $LOG 2>&1
exit 1
else
/bin/sqlplus ${arr[0]}/${arr[1]} #tst2.sql
fi
else
echo "key not found. Exiting. ==>$TIMESTAMP" $LOG 2>&1
fi
exit 0
Results (Showing 0, since there is error, should be something else other than 0).
Running Test ===>20130825-09:25
Waiting for PID:6383
Return_code=0
I also tried WHENENVER SQLERROR EXIT 1 and still getting same result of Return_code=0
Output from testing:
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SELECT COLUMN_DOES_NOT_EXIST FROM DUAL;
*
ERROR at line 2:
ORA-06550: line 2, column 10:
PL/SQL: ORA-00904: "COLUMN_DOES_NOT_EXIST": invalid identifier
ORA-06550: line 2, column 3:
PL/SQL: SQL Statement ignored
Disconnected from Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
./run.sh[38]: test: Specify a parameter with this command.
When you display your return code with this:
ret=$?
echo "Return_code=$?" >> $LOG 2>&1
... the $0 is now the result of the assignmment of ret on the previous line, not the earlier sqlplus, so it's always gping to be zero. You also have an early exit in the if block, and you won't see the messages after that, and your test condition is missing a space (and I prefer -ne to !=):
...
ret=$?
echo "Return_code=$ret" >> $LOG 2>&1
if [ $ret -ne 0 ] #if not success
then
echo "Error found...Return_code=$ret" >> $LOG 2>&1
echo "Error found...exiting program ===>$TIMESTAMP" >> $LOG 2>&1
exit $ret
else
...
I also prefer to enclose variables in braces, e.g. ${ret}, but I guess that's a matter of taste unless there is ambiguity. You can also call sqlplus with a -s flag to hide the banners in the log, incidentally.
Try adding exit at the end of your script:
WHENEVER SQLERROR EXIT SQL.SQLCODE
begin
SELECT COLUMN_DOES_NOT_EXIST FROM DUAL;
END;
EXIT;
EDIT: Assuming sqlplus returns the error code, try eliminating the background process in your script. It can be shortened to:
/bin/sqlplus ${arr[0]}/${arr[1]} #whenever.sql && /bin/sqlplus ${arr[0]}/${arr[1]} #another.sql || echo "Error..."

Resources