Print column names along with the difference in output of two tables using shell script - sql

I am trying to find out the difference between two tables in unix.
Here is the snippet of my shell script
sqlplus -s `echo $user`/`echo $password`#`echo $host`:`echo $port`/`echo $sid` #property.sql table1 table2 >1.table
sqlplus -s `echo $user`/`echo $password`#`echo $host`:`echo $port`/`echo $sid` #property.sql table2 table1 >2.table
..........................................
..........................................
diff -wy 1.table 2.table (here, option 'y' can be ommitted also)
Property.sql
SET ECHO ON
SET NEWPAGE 0
SET SPACE 0
SET PAGESIZE 0
SET FEEDBACK OFF
SET TRIMSPOOL ON
SET WRAP ON
SET VERIFY OFF
SET TAB OFF
SET HEADING ON
SET LINESIZE 4000
select property_id ,endpoint,key,value,value1,value2 from &2 where property_id in (
select table1.property_id from
(SELECT property_id,KEY,value,endpoint FROM &2
MINUS
SELECT property_id,KEY,value,endpoint FROM &1)
table1 left join &1 table2 on table1.property_id=table2.property_id) order by TO_NUMBER(property_id);
exit;
The above is printing me the difference.
I want the corresponding column names also to get printed. How to do that?

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

What is the reason for inconsistent behavior of sql query in shell script?

I have a shell script which queries the database and returns the count. Below is the code. Query returns wrong result. But when I run in some sql clients(SQL Tools and SQL Developer) result is as expected.What actually is the reason for inconsistent behavior of same query within shell script? Expected result is zero but value returned in shell script is 4. Which should be the result of select count(*) FROM schema1.emp WHERE batch_num in ('1000' ,'1001','1002'). Somehow second part of where condition is missing when I run through shell script.
#!/bin/ksh
run_query() {
(
"$SQLPLUS" -SILENT /NOLOG #/dev/stdin <<EndOfSQL
WHENEVER OSERROR EXIT FAILURE
WHENEVER SQLERROR EXIT FAILURE
CONNECT $USER/$PWD#$MY_SID
SET SERVEROUTPUT OFF;
SET TERMOUT OFF
SET TRIMSPOOL ON
SET PAGESIZE 0
SET LINESIZE 32767
SET FEEDBACK OFF
SET VERIFY OFF
SET TAB OFF
SPOOL /dev/stderr
$1
SPOOL OFF
EndOfSQL
) 3<&1 1<&2 2<&3 3<&-
}
rec_count=$(run_query " select count(*) FROM schema1.emp WHERE batch_num in ('1000' ,'1001','1002') AND stat NOT IN ('NEW','DUPLICATE');")
echo $rec_count
Thanks in advance.
select count(*)
FROM schema1.emp
WHERE batch_num in ('1000' ,'1001','1002') stat NOT IN ('NEW','DUPLICATE');
The first query is syntactically incorrect and won't execute at all. There is a AND keyword missing before stat.
select count(*)
FROM schema1.emp
WHERE batch_num = '1000'
AND batch_num = '1001'
AND batch_num = '1002'
AND stat <> 'NEW'
AND stat <> 'DUPLICATE' ;
The second query will always return zero rows. How can the condition batch_num = '1000' AND batch_num = '1001' AND batch_num = '1002' would ever be true? It would work only if it was IN, or expand it using OR conditions.

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
)

How to populate Csv file with output of SQL in unix

How to populate Csv file with output of SQL queries in unix
what i have done is
#! /bin/ksh
echo ",A,B,C\n D\n E">abc.csv
sqlplus -s scott/tiger#host<< EOF >> abc.csv
SET COLSEP ","
SET HEADING OFF
select count(a1) from tab1 where condition group by clause;
select count(b1) from tab1 where condition group by clause;
exit
EOF
uuencode abc.csv abc.csv | mailx -s "Output" email#id.com
output
a b c
d
e
result q1
{a1
b1
c1}
result q2
{
A
B
C
}
Desired output
a b c
d a1 b1 c1
e A B C
how do i get the desired output
and what needs to be done if i have to add a 'total' column after 'c' (column header)
After going through a lot, I found SET COLSEP "," was giving problem.
So what I did is, I replaced whole script to:
sqlplus -s scott/tiger#host<< EOF >/dev/null
SET HEAD OFF FEEDBACK OFF
SET LINES 100
SET PAGES 0
spool abc.csv
select a||','||b||','|| count(a1) from tab1 where condition group by clause;
spool off
EOF

Spooling data to CSV truncates

I am using the below script to output data to a csv file:
set heading off
set linesize 10000
set pagesize 0
set echo off
set verify off
spool D:\OVERNIGHT\TEMP_FILES\PFRA_DETAIL_VIXEN_OUTPUT.txt
SELECT
TRIM(T4.S_ORG_ID)||','||
TRIM(T4.NAME)||','||
TRIM(T3.CREATION_TIME)||','||
TRIM(T5.X_HOUSE_NUMBER)||','||
TRIM(T5.X_FLAT_NUMBER)||','||
TRIM(T5.ADDRESS)||','||
TRIM(T5.CITY)||','||
TRIM(T5.ZIPCODE)||','||
TRIM(T3.NOTES)
FROM TABLE_CASE T1
INNER JOIN TABLE_QUEUE T2 ON T1.CASE_CURRQ2QUEUE = T2.OBJID
INNER JOIN TABLE_PHONE_LOG T3 ON T1.OBJID = T3.CASE_PHONE2CASE
INNER JOIN TABLE_BUS_ORG T4 ON T1.X_CASE2X_BUS_ORG = T4.OBJID
INNER JOIN TABLE_ADDRESS T5 ON T1.CASE2ADDRESS = T5.OBJID
WHERE case_currq2queue IN(422);
/
spool off;
exit;
However the data is being truncated to 80 characters. The t3.notes field is in CLOB format. Does anyone know how I can spool this out to csv? I only have access to SQL*Plus.
Thanks in advance,
Steve
Try SET LONG 10000 (or whatever you need for the CLOB)
Take a look at the SET LINESIZE SQL*Plus command.