Shell Script to trigger procedure with logging - shell

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;

Related

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?

How to add if-else condition in BEGIN END statement of the input Query to SQL PLUS

I have script to load tables from flat text file, so before loading the table I want to truncate the existing tables based on input files availability.
If input file is there truncate the table and load new data from file to table.
So while truncating I want to check if input file is present, so I wrote the code like:
truncateTables()
{
QUERY_TO_TRUNCATE_TABLES="ALTER SESSION ENABLE PARALLEL DML;
whenever sqlerror exit sql.sqlcode;
BEGIN
if [$IsFile1 == 'TRUE']
then
EXECUTE IMMEDIATE 'DELETE /*+ parallel(A,8) */ FROM TableName1 A';
else
echo "no input file"
fi;
if [$IsFile2 == "TRUE"]
then
EXECUTE IMMEDIATE 'DELETE /*+ parallel(B,8) */ FROM TableName2 B';
else
echo "No input file"
fi;
COMMIT;
END;
/
";
EXECUTE_TO_TRUNCATE_TABLES=`sqlplus -s $DB_CONN_STR << EOF
SET serverout on feed off heading off tab off serverout on pagesize 0 trimspool on linesize 1000
whenever sqlerror exit sql.sqlcode;
${QUERY_TO_TRUNCATE_TABLES};
EXIT;
EOF`
retVal=$?
errorORA=`echo "${EXECUTE_TO_TRUNCATE_TABLES}" | grep -i 'ORA' | wc -l`
errorSP=`echo "${EXECUTE_TO_TRUNCATE_TABLES}" | grep -i 'SP' | wc -l`
if [[ $retVal -ne 0 || ${errorORA} -ge 1 || ${errorSP} -ge 1 ]]
then
echo "Exiting with failure.......\n$retVal\n........"
echo "Delete tables FAIL."
else
echo "tables Delete is Successful"
fi
}
But it seems we can not use if else condition in between BEGIN and end? how we can modify this code so that I can pass it to SQL PLUS? any other way also okay for me.
Actually you mixed PLSQL code and ksh.
It is possible to build your query with conditions from your kornshell. Here is how it would start:
truncateTables()
{
QUERY_TO_TRUNCATE_TABLES="ALTER SESSION ENABLE PARALLEL DML;
whenever sqlerror exit sql.sqlcode;
BEGIN
";
if [ "$IsFile1" == "TRUE" ]
then
QUERY_TO_TRUNCATE_TABLES=${QUERY_TO_TRUNCATE_TABLES}"
EXECUTE IMMEDIATE 'DELETE /*+ parallel(A,8) */ FROM TableName1 A';
;"
else
echo "no input file 1"
fi
if [ "$IsFile2" == "TRUE" ]
then
QUERY_TO_TRUNCATE_TABLES=${QUERY_TO_TRUNCATE_TABLES}"
EXECUTE IMMEDIATE 'DELETE /*+ parallel(B,8) */ FROM TableName2 B';
";
else
echo "No input file 2"
fi
QUERY_TO_TRUNCATE_TABLES=${QUERY_TO_TRUNCATE_TABLES}"
COMMIT;
END;
/
";
Hope this helps

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

Return value from sql script to shell script

I have shell script that calls the following sql script:
INSERT INTO SEMANTIC.COUNT_STATISTICS (...);
UPDATE SEMANTIC.COUNT_STATISTICS
SET PRNCT_CHANGE = 1.1;
--want to store result of this bellow select statement in model_count variable
select PRNCT_CHANGE
FROM SEMANTIC.COUNT_STATISTICS
WHERE model = '&MY_MODEL'
AND NEW_DATE = (
select max(NEW_DATE)
from SEMANTIC.COUNT_STATISTICS
where MODEL = '&MY_MODEL'
);
Now, how do I return this PERCENTAGE_NUMBER variable back to my shell script?
My shell script is as follows:
#!/bin/bash
#
# setup oracle, java, and d2rq environment
. /etc/profile.d/oracle.sh
. /etc/profile.d/java.sh
. /etc/profile.d/d2rq.sh
cd /opt/D2RQ
model_count=$(sqlplus user/pass #count.sql 'MODEL')
if ["$model_count" > 0]; then
echo "percentage count is positive"
else
echo "its negative"
I would like for that last SELECT statement result to be stored into my model_count variable in shell script.
Anyone knows why is not working?
A bash example with the use of a bash-function (note! database OS-authentication "/")
#!/bin/bash
get_count () {
sqlplus -s / <<!
set heading off
set feedback off
set pages 0
select count(*) from all_objects where object_type = '$1';
!
}
count=$(get_count $1)
echo $count
if [ "$count" -gt 0 ]; then
echo "is greater than zero"
else
echo "is less or equal to zero"
fi
~/tmp/ $ ./count.sh INDEX
2922
is greater than zero
~/tmp/ $ ./count.sh TABLE
1911
is greater than zero
~/tmp/ $ ./count.sh FUNCTION
226
is greater than zero
~/tmp/ $ ./count.sh "SUPEROBJECT"
0
is less or equal to zero
What I actually did is I separated those 2 queires and called them separatelly in my shell script:
sqlplus -S user/pass << EOF
whenever sqlerror exit 1;
set echo on
#/opt/D2RQ/model_count.sql '$MODEL' <--model_count.sql still has those INSERT & UPDATE statements
exit;
EOF
model_count=`sqlplus -S user/pass << EOF
SELECT PRNCT_CHANGE
FROM COUNT_STATISTICS
WHERE model = '$MODEL'
AND NEW_DATE = (
select max(NEW_DATE)
from COUNT_STATISTICS
where MODEL = '$MODEL'
);
exit;
EOF`
if [ $model_count >= 0 ]; then
echo "$model_count"
else
echo "'$MODEL' is negative " | mail -s "scripts issues" -c angelina1984#aol.com
fi

How can I return the number of rows affected in sqlplus to a shell script?

Here is my shell script:
# Deletes data from the 'sample' table starting August 30, 2011.
# This is done in stages with a 7 second break every
# 2 seconds or so to free up the database for other users.
# The message "Done." will be printed when there are
# no database entries left to delete.
user="*****"
pass="*****"
while(true); do
starttime=`date +%s`
while [[ $((`date +%s` - $starttime)) -lt 2 ]]; do
sqlplus $user/$pass#//blabla <<EOF
whenever sqlerror exit 1
delete from
sample
where
sampletime >= to_date('08-30-2011','mm-dd-yyyy') and
rownum <= 2;
commit;
EOF
rows = ???
if [ $rows -eq 0 ] ; then
echo "Done."
exit 0;
fi
done
sleep 7
done
If there is no way to get the number of rows, maybe I can use an error code returned by sqlplus to figure out when to end the script? Any thoughts?
Thank you!
I'd use sql%rowcount which tells you how many rows were affected by the last DML statement.
delete from
sample
where
sampletime >= to_date('08-30-2011','mm-dd-yyyy') and
rownum <= 2;
if sql%rowcount = 0 then
dbms_output.put_line('Free');
end if;
commit;
Kindly use the below
Note:-Not tested
user="*****"
pass="*****"
while(true);
do
starttime=`date +%s`
while [[ $((`date +%s` - $starttime)) -lt 2 ]];
do
rows=`sqlplus -silent $user/$pass#//blabla << EOF
whenever sqlerror exit 1
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
select count(1) from
sample
where
sampletime >= to_date('08-30-2011','mm-dd-yyyy') and
rownum <= 2;
EOF`
if [ $rows -neq 0] ;
then
sqlplus $user/$pass#//blabla << EOF1
delete from
sample
where
sampletime >= to_date('08-30-2011','mm-dd-yyyy') and
rownum <= 2;
commit;
EOF1
else
echo "Done."
exit 0;
fi
done
sleep 7
done
Please try this:
rows=`sqlplus -s ${DB_USER}/${DB_PASSWD}#${DB_SID} <<EOF
delete from sample where sampletime >= to_date('08-30-2011','mm-dd-yyyy') and rownum <= 2;
commit;
exit;
EOF`
fi
echo rows = $rows

Resources