variable value not assigned in cronjob - sql

I have a code which when executed manually ( via this command i.e. ./script.sh ) assigns the query result to a variable but when it is executed automatically via crontab then the query result is not assigned to the variable.
Please find below the code:
diff=0;
diff=`sqlplus -s user/pswd#leadb2 << END
set pagesize 0 feedback off verify off heading off echo off;
SELECT (to_Date($timeRightNow,'YYYYMMDDHH24MISS') - to_date($timeoffile,'YYYYMMDDHH24MISS') ) * 24 * 60
difference_in_minutes
from dual;
END`
echo "Difference is $diff ">>/backup2/softdev/settlement/p.txt

It usually happens because your cron is not aware of your variables initialized in .profile. Even the path for sqlplus is not available, when you run this script via cron. So, to fix the issue, set the cron job in below format, and it will work fine.
00 * * * * . ~/.profile && /home/absolut_path_to_script.sh > /home/log_file_path.txt

i have done it as cron doesnot know the path of SQLPlus so it does not execute the query as soon as the path is given to cron the job responds perfectly
Here is the solution:
ORACLE_HOME=/oracle/app/oracle/product/11.2.0/db_1
export ORACLE_HOME
dateToday=date +%Y%m%d%H%M%S
diff=0;
timeRightNow='20170519180000'
timeoffile='20170519175500'
diff=$ORACLE_HOME/bin/sqlplus -s user/paswd#leadb2 << END
set pagesize 0 feedback off verify off heading off echo off;
SELECT (to_Date($timeRightNow,'YYYYMMDDHH24MISS') - to_date($timeoffile,'YYYYMMDDHH24MISS') ) * 24 * 60
difference_in_minutes
from dual;
END
echo "Difference is $diff ">>/backup2/softdev/settlement/p.txt

Related

integer expression expected shell scripting - BASH

I am trying to get the LAG between Primary & Standby database using the below shell script. The query works fine returning the values "DATABASE IS OUTOFSYNC" or "DATABASE IS INSYNC" for an instance that has 1 Node which returns a single value, but I get an error "[: 0 1: integer expression expected" for an instance that has two Nodes which returns two values for the LAG on the first Node and the Second Node.
So here is the code:
#!/bin/bash
get_status=$(sqlplus -s "/as sysdba" <<EOF
set pagesize 0 feedback off verify off heading off echo off;
SELECT prim.seq - tgt.seq seq_gap
FROM
(
SELECT thread#, MAX(sequence#) seq, MAX(completion_time) tm
FROM
v\$archived_log
GROUP BY
thread#
)
prim,
(
SELECT thread#, MAX(sequence#) seq, MAX(completion_time) tm
FROM
v\$archived_log
WHERE
dest_id IN
(
SELECT
dest_id
FROM
v\$archive_dest
WHERE
target = 'STANDBY'
)
AND
applied = 'YES'
GROUP BY
thread#
)
tgt
WHERE
prim.thread# = tgt.thread#;
exit;
EOF
)
if [ "$get_status" -ge 5 ]; then
echo "DATABASE IS OUTOFSYNC"
else
echo "DATABASE IS INSYNC"
fi
Is there a better way to write this script?
After adding typeset -p get_status after the query and before the if I get the below results:
declare -- get_status=" 1
0"
./dgtest2.sh: line 41: [: 1
0: integer expression expected
DATABASE IS INSYNC
The query is returning more than one value/string (for 2 nodes or threads) as shown in picture/screenshot and it seems like my script is only coded to address a single value/string generated by the query.
enter image description here
Is there away to modify the script to address multiple values/strings generated by the query
The logic should be if all values returned are -ge 5 it should report "DATABASE IS OUTOFSYNC" else "DATABASE IS INSYNC" for all values returned are -lt 5.
The logic for one value -lt 5 and one value -ge 5 would not suffice as the values constantly change on the database.
Any values from 0 - 4 that the database returns whether from both Nodes should report as "DATABASE IS INSYNC" and any value from 5 upwards that the database returns whether from both Nodes should report as "DATABASE IS OUTOFSYNC".
One idea would be to capture the status values (returned by the sqlplus script) into an array and then loop through the array testing said status values.
Instead of:
variable=$(sqlplus ...)
We want:
variable=( $(sqlplus ...) )
For OP's current scripting, with a name change for the variable, we will replace this:
get_status=$(sqlplus -s "/as sysdba" <<EOF
set pagesize 0 feedback off verify off heading off echo off;
SELECT prim.seq - tgt.seq seq_gap
...
exit;
EOF
)
With this:
status_array=( $(sqlplus -s "/as sysdba" <<EOF
set pagesize 0 feedback off verify off heading off echo off;
SELECT prim.seq - tgt.seq seq_gap
...
exit;
EOF
) )
One idea for the follow-on logic testing:
default database status is INSYNC
if any status values are -ge 5 then set database status to OUTOFSYNC
The code for this looks like:
db_status='INSYNC'
for status in "${status_array[#]}"
do
[[ "${status}" -ge 5 ]] && db_status='OUTOFSYNC' && break
done
echo "DATABASE IS ${db_status}"
I'm not setup to run the sqlplus script but I should be able to simulate the results with the following array assignments:
status_array=(1)
status_array=(7)
status_array=(0 1)
status_array=(5 7)
status_array=(5 3)
Running our code for each of these array assignments gives us:
##################### status_array=(1)
DATABASE is INSYNC
##################### status_array=(7)
DATABASE is OUTOFSYNC
##################### status_array=(0 1)
DATABASE is INSYNC
##################### status_array=(5 7)
DATABASE is OUTOFSYNC
##################### status_array=(5 3)
DATABASE is OUTOFSYNC

How to run sql script in an anonymous block?

Is it possible to run an sql script in an anonymous block?
I would like to be able to conditionally run an sql script.
#!/bin/bash
.
.
.
`sqlplus -S /nolog > log3 << EOFSQL
connect ${userName}/${userPassword}#${urlDataBase};
set serveroutput on
set pagesize 0
set feedback off
set verify off
set heading off
set wrap off
set linesize 150
DECLARE
lv_error VARCHAR2(100):='';
BEGIN
SELECT TRIM(STATUS) INTO lv_error FROM tab1
WHERE ...
IF lv_error NOT LIKE 'ERROR%' THEN
START $(pwd)/script.sql;
/
END IF;
END;
/
In your case it is better to write a PL/SQL procedure and invoke it from the shell script. That way, it is easier to conditionally call the second sql function/procedure.
Or, if you want to keep the logic in shell script, spool the output of the first SQL and then read it and call the second sql script.
Something like this.
#!/bin/bash
.
.
.
sqlplus -S /nolog > log3 << EOFSQL
connect ${userName}/${userPassword}#${urlDataBase};
spool spool_out.txt
set linesize 150
DECLARE
lv_error VARCHAR2(100):='';
BEGIN
SELECT TRIM(STATUS) FROM tab1
WHERE ...
END;
/
EOFSQL
errorPresent=`cat spool_out.txt|grep "ERROR"`
if [ ! -z $errorPresent ]
the
#Call $(pwd)/script.sql;
fi

How to execute a query stored in a variable in SQL*Plus

Is there any way to pass a query to SQL*Plus through a variable?
I'm aware SQL*Plus has the capability to execute a file like:
sqlplus user/pass#db #filename
Within a kornshell script I'm trying to do:
query="select * from dual;"
sqlplus user/pass#db $query
There might have solution to do that BUT I can achieve the same goal using the following method.
[oracle#myserver Desktop]$ $ORACLE_HOME/bin/sqlplus -s jay/passsword#db <<!
select * from dual;
exit
!
D
-
X
Update, you can store the returned result in a variable as shown below.
query="select * from dual;"
var=$($ORACLE_HOME/bin/sqlplus -s jay/pass#db <<!
set pages 0
set head off
set feed off
$query
!
);

Pass shell variables to SQL statement

I want to pass shell variables to sql statement. Both shell script and SQL statement are present in the same script file.
I want the values of the variables retMonth, retLastDay and retPrvYear in the SQL statement.
Below is the code.
If I execute this, it prints - " partition_date between '01--' and '--' \ 0 0] 1 1] 12-DEC-14 1"
How can I have values of retMonth, retLastDay and retPrvYear in SQL statement?
echo $retMonth //This prints 07
echo $retLastDay //This prints 31
echo $retPrvYear //This prints 2015
count=$(sqlplus -s ${DBA_ORACLE_USER}/${DBA_ORACLE_PWORD}#${ORACLE_SID} <<END
#connect ${DBA_ORACLE_USER}/${DBA_ORACLE_PWORD}#${ORACLE_SID}
set serveroutput on
set linesize 1000
set heading off
set feedback off
define lastMonth=$retMonth
define lastYear=$retPrvYear
define lastDay=$retLastDay
SELECT count(1)
FROM MYTABLE
WHERE partition_date between '01-$lastMonth-$lastYear' and '$lastDay-$lastMonth-$lastYear'
);
END
)
Try using quoted shell variables directly without using define directives:
count=$(sqlplus -s "${DBA_ORACLE_USER}/${DBA_ORACLE_PWORD}#${ORACLE_SID}" <<END
set serveroutput on
set linesize 1000
set heading off
set feedback off
SELECT count(1)
FROM MYTABLE
WHERE partition_date between
"01-$retMonth-$retPrvYear" and "$retLastDay-$retMonth-$retPrvYear";
END
)

Store SQL query string into variable BASH

I have a select statement inside a bash script that returns the latest date in the DB. I run this query 4 times so I want to define it just once and assing the text to a variable.
#!/bin/bash
linux commands;
database_date=$(sqlplus -s/nolog $USER/$USER#BRMDPP <<END
set pagesize 0 feedback off verify off heading off echo off;
SELECT ...
exit;
END
)
commands that change the database date;
last_date=$(sqlplus -s/nolog $USER/$USER#BRMDPP <<END
set pagesize 0 feedback off verify off heading off echo off;
SELECT ...
exit;
END
)
commands that change the database date;
How can I store this big string $(sqlplus ... into one variable and use it again?
Thank you
One way would be to make use of a function:
foo() {
sqlplus -s/nolog $USER/$USER#BRMDPP <<END
set pagesize 0 feedback off verify off heading off echo off;
SELECT ...
exit;
END
}
and later invoke it by saying:
value=$(foo)
In order to get the value returned by the function, say echo "$value" (note that quoting variables is important).