Pass values read from a file as input to an SQL query in Oracle - oracle

#cat file.txt
12354
13456
13498
#!/bin/bash
for i in `cat file.txt`
do
sqlplus XXXXX/XXXXX#DB_NAME << EOF
select *from TABLE_NAME where id="$i"
EOF
done
This is not working for me. Help me how I can solve this.

The solution given by #codeforester works. However I was unable to use it because it created as many DB connections as the number of lines in your file which is a potential impact.
To overcome this, I chose the below solution which may not be ideal but does the job with just one DB connection.
Considering the same data in file.txt
12354
13456
13498
I used the below sed command to populate the above to a single variable "12354,13456,13498"
myvariable=$(echo "`cat file.txt | sed '$!s/$/,/g' | tr -d '\n' | tr -d ' '`")
Now below script will pass this variable to the SQL query and spool the data into a text file:
#!/bin/bash
myvariable=$(echo "`cat file.txt | sed '$!s/$/,/g' | tr -d '\n' | tr -d ' '`")
echo #myvariable
sqlplus /nolog << EOF
CONNECT user#dbname/dbpassword
SPOOL dboutput.txt
select column1 from table_name where id in ($myvariable);
SPOOL OFF
EOF
The output is stored in dboutput.txt (along with the SQL query)
cat dboutput.txt
SQL> select column1 from table_name where id in (12354,13456,13498);
NAME
---------------------------------------------------------------------------- ----
data1
data2
data3
SQL> spool off

Here is the right way to use the heredoc <<, along with the choice of while read instead of for to read the file:
#!/bin/bash
while read -r value; do
sqlplus xxxxx/xxxxx#db_name << EOF
select * from table_name where id='$value';
# make sure heredoc marker "EOF" is not indented
EOF
done < file.txt
See also:
How can I write a here doc to a file in Bash script?
BashFAQ001 to understand why for loop is not the best way to read text lines from a file.

Related

Bash HEREDOC Single Quotes around expanded variable

I need the $table var to expand but while keeping the quotes that are required by MSSQL for the table_name parameter. I don't know if this is possible as I have been searching for a while. The common answer I see is if there are any quotes then variables won't be expanded. Is it simply not possible to do what I need here?
Code
cat <<EOF | isql $host sa 'password' -d, | sed '-e 1,10d;$d' | sort > mssql_table_${table}_column_info
use $database;
select column_name from information_schema.columns where table_name = '$table';
EOF
Desired Output
select column_name from information_schema.columns where table_name = 'mytable_name';
Notice that the output has single quotes still around the table name. This is necessary for MSSQL to select the appropriate table.
Are you sure the variable expansion in the here document is the problem though? If you just inspect the output of the cat command (using bash):
$ database=database123 table=mytable_name cat <<EOF >/dev/stdout
use $database;
select column_name from information_schema.columns where table_name = '$table';
EOF
use database123;
select column_name from information_schema.columns where table_name = 'mytable_name';
You might want to break down what the other commands are doing to make sure where the error is.
On a side note, your mention of turning off the variable expansion via quotation marks (' or ") apparently conflates the syntax of the here document with the unrelated syntax of other commands in the pipeline.
For example this is correct:
### works, prints 'hello hello'
MYVAR='hello' cat <<EOF | grep 'hello hello'
hello $MYVAR
EOF
As opposed to:
### WRONG, response empty
MYVAR='hello' cat <<'EOF' | grep 'hello hello'
hello $MYVAR
EOF
Does not perform the variable substitution, because the word 'EOF' is quoted in the here document, turning off variable expansion. This is regardless of whether other commands in the pipeline, that is grep 'hello hello', have quotes or not.

Why a new line character appending to shell variable?

I have used the method to assign the SQL output to a variable as below.
dbRole=$(${SQLPLUSPGM} -s / as sysdba <<-EOF
set head off
set verify off
set feedback off
select trim(translate(database_role,' ','_')) from v\$database;
exit;
EOF
)
But the variable o/p appending a "\n" character i.e \nPHYSICAL_STANDBY
However, when I use the below method it is working fine
${SQLPLUSPGM} -s / as sysdba <<-EOF | grep -v '^$' | read dbRole
set head off
set verify off
set feedback off
select trim(translate(database_role,' ','_')) from v\$database;
exit;
EOF
Any suggestion why it is appending `\n' and how we can get rid of it.
Appreciate your suggestions.
Your second method, with the grep -v, removes the additional line.
You can use some filter inside your first method with additional parentheses.
dbRole=$((cat | grep -v "^$") <<-EOF
1
2
3
5
EOF
)
Alternative filters with some differences are grep ., head -1, sed '$d'.

delete rows from databse using a shell script

the below script gives me an error. Basically I am trying to delete the records that I got from the first query. I have put them in a text file, formatted them and used them in the delete operation.
After executing the script I am getting the below error:-
: line 5: syntax error at line 27: `<<' unmatched
Can't tell because the code you dumped is unformatted, but my first guess would be you have leading spaces in front of the EOF in your here document.
This should work (note that there are no leading spaces in front of the EOF.:
sqlplus -s $dbcreds << EOF > output.txt
SET SERVEROUTPUT OFF
select empname from emp where dept_no=123;
EOF
if [ -s "output.txt" ]
then
echo " Found the below employees....Deleting them from Database ..............!!!! \n"
cat output.txt
sed "s/(.*)/'\1'/" output.txt| tr '\n' ','|sed 's/.$//' >final_employees.txt
while read line
do
sqlplus -s $dbcreds <<EOF
SET SERVEROUTPUT OFF
Delete from emp where empname in ($line);
EOF
done < final_employees.txt
else
echo " No employees found....!!!"
fi

line 45: syntax error: unexpected end of file

When I try running the script, I am gettin the error line 45: syntax error: unexpected end of file. I am relatively new to scripting. Please help me resolve it.
#!/bin/ksh
set -xv
export HOME=/home/mine
. $HOME/.env.ksh
BIS_SPOOL=/tmp/bis_table_mine.spl
BIS_REPORT_MINE=/tmp/bis_table_report_mine.txt
touch $BIS_SPOOL
rm $BIS_SPOOL
touch $BIS_SPOOL
exec 5< $BIS_REPORT_MINE
while read -u5 REC_MINE
do
TBLENAME=`echo "$REC_MINE" | awk '{print $3}' | tr '[:upper:]' '[:lower:]'`
sqlplus -s ${USER_ID}/${USER_PASS}#${ORACLE_SID} <<- EOF
set feedback off
set hea ON
set pagesize 9999
set linesize 9999
set trimspool ON
set termout off
spool $BIS_SPOOL append
Column C1 Heading 'Job Name' Format a30
Column C2 Heading 'Table Name' Format a30
SELECT job_name C1,
table_name C2,
FROM table_usage
WHERE table_name like 'TBLENAME%'
/
exit;
EOF
done
exec 5<& -
The <<- EOS is interpreted literally. Make it
sqlplus -s ${USER_ID}/${USER_PASS}#${ORACLE_SID} <<-EOF
without the space char.
Also make sure there is no space char before or after your closing EOS , but leading tab chars are allowed.
IHTH

ORACLE: need to export table data without spaces between columns

Say i have Table A with columns
col1 col2 col3 col4
-------------------
sajal singh 28 IND
hello how are you
I want to export the data into a flat file without spaces or tabs between columns
So the output should be
cat dump
sajalsingh28IND
hellohowareyou
what i have tried. i have written a script
#!/usr/bin/bash
#the file where sql output will go
OUT=report.txt
>$OUT
DESC=desc.txt
>$DESC
sqlplus -s "xxx/xxx#xxx" << END_SQL > /dev/null
set pages 0
set feedback off
set heading off
set trimspool off
set termout off
set verify off
set wrap off
SPOOL $DESC
Select * from table_name;
SPOOL OFF
END_SQL
But i am getting outputs of one row in multiple lines and with tabs/spaces
So question is how can i fix that? and
I found some data pump utilities like expdp. Can i use that in Unix? if yes, how can i acheive the dump in that format?
Thank You
If you already have a CSV dump, then you can run the following command:
awk 'BEGIN{FS=",";OFS=""}{$1=$1}1' csv.dump > new.dump
Untested:
SET HEADING OFF
SET FEEDBACK OFF
SPOOL $DESC
SELECT col1 ||''|| col2 ||''|| col3 FROM table_name;
SPOOL OFF;
From a "simplified oracle view" to "plain" characters with sed:
sed -n '3,$ s/\s//gp' file
$cat file
col1 col2 col3 col4
-------------------
sajal singh 28 IND
hello how are you
$sed -n '3,$ s/\s//gp' file
sajalsingh28IND
hellohowareyou
Explanation: replace all white space (not line breaks) from line 3 to EOF with "nothing".
If you want the columns padded out but no additional spaces between the columns you can do:
set colsep ""
The default is to have a single space between the double-quotes, which puts a single space between the columns. You might also want to do:
set tab off
... to ensure that multiple spaces in the padding isn't converted to tabs, which looks fine for display but would be a pain parsing the file.
If you want no spaces at all, to do this within SQL*Plus you'd need to concatenate the columns:
select col1 || col2 || col3 || col4 from table_name;
This is useful if you're putting a delimiter between the columns (e.g. making it a CSV), but I don't know what you'd be able to do with the data in the file if you squashed everything together without delimiters.
So this is what i came up with: it will dump oracle data without any spaces etc between columns, while preserving the spaces within data. I thought i would share it with you.
#!/usr/bin/bash
#the file where sql output will go
OUT=report.txt
>$OUT
DESC=desc.txt
>$DESC
TABLE_NAME=$1
###GET DESCRIBE####
s=""
#######################
sqlplus -s "xxx/xxx#xxx" << END_SQL > /dev/null
set pages 0
set feedback off
set heading off
set trimspool off
set termout off
set verify off
set wrap off
SPOOL $DESC
desc $TABLE_NAME;
SPOOL OFF
END_SQL
#######################
for i in `cat $DESC|awk -F" " '{print $1}'|grep -v -i name|grep -v -`
do
s=$s"trim($i)||'|'||"
done
s=`echo $s|sed "s/||'|'||$//g"`
echo $s
#######################
#sqlplus - silent mode
#redirect /dev/null so that output is not shown on terminal
sqlplus -s "xxx/xxx#xxx" << END_SQL > /dev/null
set pages 0
set feedback off
set heading off
set trimspool off
set termout off
set verify off
set colsep ""
set tab off
set lines 1500
SPOOL $OUT
select $s from $TABLE_NAME;
SPOOL OFF
END_SQL
#######################
cat $OUT|sed "s/|//g"|sed "s/ *$//g" >$OUT.new
mv $OUT.new $OUT
echo Finished writing report $OUT

Resources