sqlplus Input redirection on bash - linux

New to sqlplus/bash scripting. I currently have a simple script that fetches some value in a table based on some ID values.
#do things. get login info. etc....
(cat<<HERE
set heading off;
select data_value from metadata where name='JOHN' and uniqueid in (1, 2, 3);
EOD
) | sqlplus -S $login
#do things.
What if instead of having to manually type of the ids (1, 2, 3, etc...), I do this:
#calls a script that gets the IDs from somewhere and outputs it in the correct format
./getIDscript > IDs
#do things. get login info. etc....
(cat<<HERE
set heading off;
select data_value from metadata where name='JOHN' and uniqueid in ($IDs);
EOD
) | sqlplus -S $login
#do things.
Would this work? I currently won't have access to the school lab for a few days so I can't test this out right now.
Is there a better and more efficient way of doing this?

Try this :
sqlplus -S /nolog <<_EOD1
WHENEVER SQLERROR EXIT SQL.SQLCODE
connect usr/xxx#db1
select 1 from dual
/
exit
_EOD1

Related

Unable to append the output of for loop

I am trying to get tablespace total space for those tablespaces where given threshold is breached.
As I am getting more than one tablespaces in output , I am splitting those and after that running a for loop on array. Now I need to get bytes for each i but its only printing value of first occurrence. How should I append all the values?
Please check below code:
output1=`sqlplus -s username/password as sysbackup <<END1
set linesize 200
set head off
select tablespace_name||',' from dba_tablespace_usage_metrics where used_percent > 50;
exit;
END1`
IFS=', ' read -r -a array <<< $output1
for val in "${array[#]}"
do
output2=`sqlplus -s username/password as sysbackup <<END2
set serveroutput on;
set linesize 200
set head off
spool test.txt
SELECT TABLESPACE_NAME, ROUND (SUM (BYTES) / 1048576) FROM DBA_DATA_FILES WHERE TABLESPACE_NAME = '${array[val]}' GROUP BY TABLESPACE_NAME;
spool off;
#test.txt
exit;
END2`
done
#test.sql should print :
SYSAUX 2048
SYSTEM 4027
but its only printing:
SYSAUX 2048
Your code isn't printing anything from the loop at the moment; if you print $output2 after the loop then you'd see that value once; if you did it inside the loop then you'd see it multiple times, with the same value. Each output would also plus an SP-0734 error, which you may be supressing.
When you write to test.txt you're putting the result of the query against dba_data_files into that file; and $val has the value form the array not an index, so ${array[val]} doesn't mean what you probably think, and always gives you the first element in the array; so each time around the loop you've got the same result from the same query in test.txt.
Then you execute that, which gets an error. But both the initial query and that error is all being captured into output2 - just as you'd see it all if you ran test.txt manually. And that is overwritten each time. So if you process/display it inside the loop you'd see the same result repeated; if you ran it after the loop (which is what you seem to be doing, from your description) then you'd see it once.
If you really wanted to append the output each time around the loop you could do:
output2=${output2}`sqlplus -s username/password as sysbackup <<END2
...
END2`
or:
output2+=`sqlplus -s username/password as sysbackup <<END2
...
END2`
but you would need to clean up the output that both queries are producing, and then might need to include a newline in that concatenation.
This would be much simpler as a single query, which just outputs directly instead of to a variable:
sqlplus -s username/password as sysbackup <<END1
set pagesize 0
set linesize 200
set feedback off
SELECT TABLESPACE_NAME, ROUND (SUM (BYTES) / 1048576)
FROM DBA_DATA_FILES
WHERE TABLESPACE_NAME IN (
select tablespace_name
from dba_tablespace_usage_metrics
where used_percent > 50
)
GROUP BY TABLESPACE_NAME
ORDER BY TABLESPACE_NAME;
END1
If you don't want the column alignment then concatenate the name and size values:
SELECT TABLESPACE_NAME || ' ' || ROUND (SUM (BYTES) / 1048576)

Bash script with multiline heredoc doesn't output anything

I'm writing a script to send SQL output in mail, but it is not executing successfully and is not generating the output I want.
The query generates two columns with multiple rows. How can I generate the output in table format as below?
Below is my code:
#!/bin/bash
ORACLE_HOME= **PATH
export ORACLE_HOME
PATH=$PATH:$ORACLE_HOME/bin
export PATH
TNS_ADMIN= ** PATH
export TNS_ADMIN
today=$(date +%d-%m-%Y)
output=$(sqlplus -S user/pass#service <<EOF
set heading off;
SELECT distinct list_name ,max(captured_dttm) as Last_received FROM db.table1
group by list_name having max(captured_dttm) <= trunc(sysdate - interval '2' hour);
EOF)
if [ -z "$output" ];
then
echo"its fine"
exit
else
echo "
Dear All,
Kindly check we've not received the list for last 2 hour : $output
Regards,
Team" | mailx -S smtp=XX.XX.X.XX:XX -s "URGENT! Please check list FOR $today" user#abc.com
fi
When using a here document, the closing string can't be followed by anything but a newline. Move the closing parenthesis to the next line:
output=$(sqlplus -S user/pass#service <<EOF
...
EOF
)

Excel file generation using SQL query, SPOOL command in Shell script

I have to generate excel file from tables from Oracle Database. The code is working fine but however the column names are not coming completely, there are just coming as the length of there data length.
I want complete header/column names
The column names are coming like this
ST STAT_TYPE_DESC ST S NXT_STATME DELAY_DAYS ANN_PREM_LIM_LOW ANN_PREM_LIM_HI CONTRIB_HIST_LEN EVENT_DO C P
But I want is complete names of the columns, for example ST is STATEMENT_TYPE_ID
#!/bin/ksh
FILE="A.csv"
sqlplus -s lifelite/lifelite#dv10 <<EOF
SPOOL $FILE
SET HEADING ON
SET HEADSEP OFF
SET FEEDBACK OFF
SET LINESIZE 250
SET PAGESIZE 5000 embedded ON
SET COLSEP ","
SELECT * FROM TLLI_01150STATTYPE;
EOF
SPOOL OFF
EXIT 0
Before your select add a new one with the column names:
SELECT 'STATEMENT_TYPE_ID' || ',' || 'STAT_TYPE_DESC' || ',' || ... FROM dual;
And set heading off

shell script has been retrieving from edbplus sql results with echo outputs

I am trying to call edbplus to count a table from a command-line linux shell script, but I have been retrieving from edbplus the response number with others outputs in the same response, I am trying to retrieve from it only an integer response number.
#!/bin/sh
COUNT=`./edbplus.sh -silent user/password#localhost:5444/mydb<<-EOF
SET PAGESIZE 0 FEEDBACK OFF VERIFY OFF HEADING OFF ECHO OFF
SELECT COUNT(ID) FROM MYTABLE
EXIT;
EOF`
echo $COUNT
Response:
$ echo $COUNT
6-------------------d always takes 2 parameters: variable_name value
Do you know how get only the integer number?
If the 1st value is going to be integer. Please try the below commands
echo $COUNT | cut -d - -f 1
(or)
if only one int value if required, then please try
echo $COUNT | cut -c 1
To solve it from EDB perspective:
If the below flags are used in EDB in single line, then the above issue would have caused.
SET PAGESIZE 0
SET FEEDBACK OFF
SET VERIFY OFF
SET HEADING OFF
SET ECHO OFF
Kindly update it as above and provide it in individual lines.

Stopping the shell script if any of the query gets failed

Below is my shell script from which I am trying to invoke few hive SQL queries which is working fine.
#!/bin/bash
DATE_YEST_FORMAT1=`perl -e 'use POSIX qw(strftime); print strftime "%Y-%m-%d",localtime(time()- 3600*504);'`
echo $DATE_YEST_FORMAT1
hive -e "
SELECT t1 [0] AS buyer_id
,t1 [1] AS item_id
,created_time
FROM (
SELECT split(ckey, '\\\\|') AS t1
,created_time
FROM (
SELECT CONCAT (
buyer_id
,'|'
,item_id
) AS ckey
,created_time
FROM dw_checkout_trans
WHERE to_date(from_unixtime(cast(UNIX_TIMESTAMP(created_time) AS BIGINT))) = '$DATE_YEST_FORMAT1' distribute BY ckey sort BY ckey
,created_time DESC
) a
WHERE rank(ckey) < 1
) X
ORDER BY buyer_id
,created_time DESC;"
sleep 120
QUERY1=`hive -e "
set mapred.job.queue.name=hdmi-technology;
SELECT SUM(total_items_purchased), SUM(total_items_missingormismatch) from lip_data_quality where dt='$DATE_YEST_FORMAT2';"`
Problem Statement:-
If you see my first hive -e block after the echo $DATE_YEST_FORMAT1. Sometimes that query gets failed due to certain reasons. So currently what happens is that, if the first Hive SQL query gets failed, then it goes to second Hive SQL query after sleeping for 120 seconds. And that is the thing I don't want. So Is there any way if the first query gets failed dues to any reasons, it should get stopped automatically at that point. And it should start running automatically from the starting again after few minutes(should be configurable)
Update:-
As suggested by Stephen.
I tried something like this-
#!/bin/bash
hive -e " blaah blaah;"
RET_VAL=$?
echo $RET_VAL
if [ $RET_VAL -ne 0]; then
echo "HiveQL failed due to certain reason" | mailx -s "LIP Query Failed" -r rj#host.com rj#host.com
exit(1)
I got something like this below as an error and I didn't got any email too. Anything wrong with my syntax and approach?
syntax error at line 152: `exit' unexpected
Note:-
Zero is success here if the Hive Query is executed successfully.
Another Update after putting the space:-
After making changes like below
#!/bin/bash
hive -e " blaah blaah;"
RET_VAL=$?
echo $RET_VAL
if [ $RET_VAL -ne 0 ]; then
echo "HiveQL failed due to certain reason for LIP" | mailx -s "LIP Query Failed" -r rj#host.com rj#host.com
fi
exit
hive -e 'Another SQL Query;'
I got something like below-
RET_VAL=0
+ echo 0
0
+ [ 0 -ne 0 ]
+ exit
Status code was zero as my first query was successful but my program exited after that and it didn't went to execute my second query? Why? I am missing something here for sure again.
You may also find useful setting the exit immediately option:
set -e Exit immediately if a simple command (see SHELL GRAMMAR
above) exits with a non-zero status. The shell does not
exit if the command that fails is part of the command
list immediately following a while or until keyword,
part of the test in an if statement, part of a && or ||
list, or if the command's return value is being inverted
via !. A trap on ERR, if set, is executed before the
shell exits.
as in this example
#!/bin/bash
set -e
false
echo "Never reached"
Unless I'm misunderstanding the situation, it's very simple:
#!/bin/bash
DATE_YEST_FORMAT1=`perl -e 'use POSIX qw(strftime); print strftime "%Y-%m-%d",localtime(time()- 3600*504);'`
echo $DATE_YEST_FORMAT1
QUERY0="
SELECT t1 [0] AS buyer_id
,t1 [1] AS item_id
,created_time
FROM (
SELECT split(ckey, '\\\\|') AS t1
,created_time
FROM (
SELECT CONCAT (
buyer_id
,'|'
,item_id
) AS ckey
,created_time
FROM dw_checkout_trans
WHERE to_date(from_unixtime(cast(UNIX_TIMESTAMP(created_time) AS BIGINT))) = '$DATE_YEST_FORMAT1' distribute BY ckey sort BY ckey
,created_time DESC
) a
WHERE rank(ckey) < 1
) X
ORDER BY buyer_id
,created_time DESC;"
if hive -e "$QUERY0"
then
sleep 120
QUERY1=`hive -e "
set mapred.job.queue.name=hdmi-technology;
SELECT SUM(total_items_purchased), SUM(total_items_missingormismatch) from lip_data_quality where dt='$DATE_YEST_FORMAT2';"`
# ...and whatever you do with $QUERY1...
fi
The string $QUERY0 is for convenience, not necessity. The key point is that you can test whether a command succeeded (returned status 0) with the if statement. The test command (better known as [) is just a command that returns 0 when the tested condition is met, and 1 (non-zero) when it is not met.
So, the if statement runs the first hive query; if it passes (exit status 0), then (and only then) does it move on to the actions in the then clause.
I've resisted the temptation to reformat your SQL; suffice to say, it is not the layout I would use in my own code.

Resources