What is wrong with this perl script - oracle

Below is the Perl script that I have written
my $COUNT_1;
my $parameter1 = 'PU_CLERK';
$COUNT_1 = `sqlplus -s hr/password\#dbname\#sql_script.sql $parameter1`;
SQL SCRIPT:
select count(*) from employees
where job_id <> '&1'
and salary > 9000
and commission_pct is not null
order by first_name desc
/
exit;
When I run this query by passing the argument &1 it is giving me a string with an error message. But when I run the same query by hardcoding I'm getting the output properly (the count is 15 which is the correct answer).
select count(*) from employees
where job_id <> 'PU_CLERK'
and salary > 9000
and commission_pct is not null
order by first_name desc
/
exit;
I'm not able to understand where I'm going wrong. How do I pass parameters in Perl. We used to do the same way in shell script and it was working absolutely fine.
EDIT:
This is the error message im getting
perl call_sql.pl
value of first variable isold 2: whe
re job_id <> '&1'
new 2: where job_id <> 'PU_CLERK'
15
So its basically not printing the 15 value its printing all those string also when i use '&1' in my sql script
EDIT2:
Hi Guys finally it is working. In my sql code instead of giving '&1' i gave '$1' Now i want to know is $1 of some significance in Perl? Thanks..

I don't know the answer to your current problem, but using the DBI module is the better solution, so I wrote a sample script to get you started. You may need to tweak some things to get it to work.
use strict;
use warnings;
use DBI;
my $dbname = "mydb";
my $user = "foo";
my $passwd = "bar";
my $dbh = DBI->connect("dbi:Oracle:$dbname", $user, $passwd)
or die $DBI::errstr;
my $parameter1 = 'PU_CLERK';
my $statement = "select count(*) from employees
where job_id <> ?
and salary > 9000
and commission_pct is not null
order by first_name desc";
my $sth = $dbh->prepare($statement) or die $dbh->errstr;
$sth->execute($parameter1) or die $sth->errstr;
while (my $row = $sth->fetchrow_arrayref) {
print "#$row"; # or whatever you want to do with it
}
$dbh->disconnect or warn $dbh->errstr;

This has nothing with perl.
Proof: make an shell script, say mytest.sh with the next content:
#!/bin/bash
echo "$0: Got $# args" >&2 #to stderr
i=0
for arg
do
let i++
echo "$0: arg($i)=$arg=" >&2 #to stderr
done
echo "15" #result to stdout
make it executable, with chmod 755 mytest.sh
Now modify your perl script as:
my $COUNT_1;
my $parameter1 = 'PU_CLERK';
$COUNT_1 = `./mytest.sh -s hr/password\#dbname\#sql_script.sql $parameter1`;
print "script returned: $COUNT_1\n";
run it
$ perl script.pl
result:
./mytest.sh: Got 3 args
./mytest.sh: arg(1)=-s=
./mytest.sh: arg(2)=hr/password#dbname#sql_script.sql=
./mytest.sh: arg(3)=PU_CLERK=
script returned: 15
e.g. the perl
correctly run the external script
correctly passes the arguments to it
so, search for the error in the sqlplus doccumentation...

Related

How to get plain formatted output in csv with shell script for oracle sql query

This is my shell script.
echo "Start";echo #/opt/apps/Tests/SQLDir/Test1.sql | sqlplus Db1/Db1#//maydomain:port/abc;echo "Finish";
echo "Start";echo #/opt/apps/Tests/SQLDir/Test2.sql | sqlplus Db1/Db1#//maydomain:port/abc;echo "Finish";
I have 30 .sql files like this, added in one .sh file which results 30 .csv files
Test1.sql has
SPOOL /opt/apps/Tests/OF/output1.csv REPLACE;
select name from username where id = 10 and Sname is not NULL and ROWNUM < = 50000;
Test2.sql has
SPOOL /opt/apps/Tests/OF/output2.csv REPLACE;
select strname,ctyname from addr where city = 'NYC' and ROWNUM < = 50000;
My expected OP in output1.csv is
name
Abc
xyz
pqr
My expected OP in output2.csv is
strname | ctyname
10-AP NYC
11-KP MCH
90-ZP SDK
right now I am getting weird o/p in csv
name
-------------------------------
Abc
xyz
pqr
name
-------------------------------
TYU
KLH
50000 rows selected.
SQL>
So is there any way to remove those additional lines [--------- and 50000 rows selected.] with shell script/sql code?
And while executing shell script all sql result rows are getting printed on screen. how to avoid that?
Thanks in advance.
Following SQL*Plus command should do the job:
set markup csv on delimiter ' ' quote off
set feedback off
I must say, your method of passing the name of a script to sqlplus is the strangest I've ever seen. The usual practice (given your names) would be:
sqlplus Db1/Db1#//maydomain:port/abc #/opt/apps/Tests/SQLDir/Test1.sql
I don't see where your 'echo Start' and 'echo finished' accomplish anything, since there is no clarifying info coming along with it.
It looks to me like what you want in your scripts would be
set echo off trimsp on head off pagesize 0
spool /opt/apps/Tests/OF/output2.csv replace
select strname,ctyname from addr where city = 'NYC' and ROWNUM < = 50000;
spool off
BTW, 'spool' is a sqlplus command - a directive to sqlplus itself, not a sql statement. As such, it does not need a semi-colon at the end.
-- edit
Example of using environment variables on sqlplus command line:
username=scott
userpw=tiger
server=myserver
port=1521
dbname=mydb
sqlplus $username/$userpw#//$server:$port/$dbname
Though I would question why you need to set them as variables.
And I prefer to use tnsnames rather than ezconnect.

unable to loop through array in bash for PostgreSQL query export

I have a PostgreSQL query that I'd like to run for multiple geographic areas via a loop. I want to use the elements in the array to modify the query and the name of the csv file where I'm exporting the data to. So in essence, I want the query to run on ...cwa = 'MFR'... and export to hourly_MFR.csv, then run on ...cwa = 'PQR'... and export to hourly_PQR.csv, and so on.
Here's what I have so far. I thought maybe the EOF in the script might be causing problems, but I couldn't figure out how to get the loop to work while maintaining the general format of the script.
Also, the query/script, without the looping (excluding declare, for, do, done statements) works fine.
dbname="XXX"
username="XXXXX"
psql $dbname $username << EOF
declare -a arr=('MFR', 'PQR', 'REV')
for i in "${arr[#]}"
do
\COPY
(SELECT d.woyhh,
COALESCE(ct.ct, 0) AS total_count
FROM
(SELECT f_woyhh(d::TIMESTAMP) AS woyhh
FROM generate_series(TIMESTAMP '2018-01-01', TIMESTAMP '2018-12-31', interval '1 hour') d) d
LEFT JOIN
(SELECT f_woyhh((TIME)::TIMESTAMP) AS woyhh,
count(*) AS ct
FROM counties c
JOIN ltg_data d ON ST_contains(c.the_geom, d.ltg_geom)
WHERE cwa = $i
GROUP BY 1) ct USING (whh)
ORDER BY 1) TO /var/www/html/GIS/ltg_db/bigquery/hourly_$i.csv CSV HEADER;
done
EOF
Thanks for any help!
I think you are nearly there, you just have to reorder some lines. Try this:
dbname="XXX"
username="XXXXX"
declare -a arr=('MFR', 'PQR', 'REV')
for i in "${arr[#]}"
do
psql $dbname $username << EOF
\COPY
(SELECT d.woyhh,
COALESCE(ct.ct, 0) AS total_count
FROM
(SELECT f_woyhh(d::TIMESTAMP) AS woyhh
FROM generate_series(TIMESTAMP '2018-01-01', TIMESTAMP '2018-12-31', interval '1 hour') d) d
LEFT JOIN
(SELECT f_woyhh((TIME)::TIMESTAMP) AS woyhh,
count(*) AS ct
FROM counties c
JOIN ltg_data d ON ST_contains(c.the_geom, d.ltg_geom)
WHERE cwa = $i
GROUP BY 1) ct USING (whh)
ORDER BY 1) TO /var/www/html/GIS/ltg_db/bigquery/hourly_$i.csv CSV HEADER;
EOF
done
The declare and the for loop are part of the bash script while everything between <<EOF and EOF are part of your Postgresql query.
In #Lienhart Woitok's answer above, the solution will definitely work. However - note that this has the side effect of executing a new 'psql' call, database connection setup, authentication, and subsequent response returned; followed by closing the connection - for each iteration of the loop.
In this case you are only running 3 iterations of the loop, so it may not be a significant issue. However, if you expand the usage to run more iterations, you may want to optimize this to only run a single DB connection and batch query it.
To do that, use of a temporary working file to build the SQL commands may be necessary. There are other ways, but this is relatively simple to use and debug:
QUERY_FILE=$(mktemp /tmp/query.XXXXXXX)
# note the use of an array isn't really necessary in this use
# case - and a simple set of values can be used equally as well
CWA="MFR PQR REV"
for i in $CWA
do
cat <<EOF >> $QUERY_FILE
<ADD_YOUR_QUERY_STATEMENTS_HERE>
EOF
done
psql --file=$QUERY_FILE $dbname $username
if (( $? ))
then
echo "query failed (QUERY_FILE: ($QUERY_FILE')"
exit 1
else
echo "query succeeded"
rm -f $QUERY_FILE
exit 0
fi

How to use a variable from Bash into SQLPLUS?

I'm trying to write a script which would accept the customer ID using BASH ( using a basic read command ) and then I want to use that BASH variable in my SQLPLUS query. How can I do that ? I'm trying to use below format, but it is not working.
echo "Enter Customer ID :- ";
read Customer
sqlplus username\password#host
select first_name from customer where customer_id = $Customer;
quit
exit
Typically, you would do:
echo "select first_name from customer where customer_id = $Customer;" | sqlplus username\password#host
If you want to run multiple queries, it is common to use a heredoc:
cat << EOF | sqlplus username\password#host
select first_name from customer where customer_id = $Customer;
select first_name from customer where customer_id = $Customer;
EOF
edited in response to query in comment:
to store the result of any command in a variable you can use process substitution. var=$( cmd ). In the heredoc case, the syntax is:
var=$( cat << EOF | sql...
query
query
EOF
)

Variable won't resolve inside PL-SQL statement

I am trying to pass a SQL command to the SQL*Plus command-line program (Oracle) in my KornShell (ksh) script, but my $MY_VAR variable seems to be failing to resolve. $MY_VAR is a string value.
sqlplus -s << EOF >> $LOG_FILE
$MY_SCHEMA
UPDATE my_table SET run_flag = 'I', start_time = to_char(sysdate, 'DD-Mon-YYYY HH24:MI:SS') WHERE (process_id = '$MY_VAR' AND run_flag != 'F');
COMMIT;
EOF
I can successfully echo out the $MY_VAR variable, and so I can see that the variable is populated, but it does not seem to be resolving when inserting the variable into the SQL command which I am providing as an argument to the SQL*Plus program. The log file for the script simply outputs:
0 rows updated. Commit complete.
The SQL seems to be valid as we can successfully execute the command in SQL Developer (albeit with a hardcoded value for $MY_VAR).
Any ideas on what I am missing here?
Thank you
Try this:
sql="$MY_SCHEMA
UPDATE my_table SET run_flag = 'I', start_time = to_char(sysdate, 'DD-Mon-YYYY HH24:MI:SS') WHERE (process_id = '$MY_VAR' AND run_flag != 'F');
COMMIT;"
print "$sql"
sqlplus -s <<<"$sql" >> $LOG_FILE
Does the sql look correct? If it does and zero rows are updated, your where clause must be selecting zero rows.
Your version of ksh may not have the <<< here-string syntax. In that case:
print "$sql" | sqlplus -s >> $LOG_FILE

unix shell script to check result of sql query

I have the code like this
v_use_xref_result=`sqlplus -s $UP <
Select Code_Desc
From Code_Detail
Where Code='UXLOC'
and CODE_TYPE='UXRF'
EOF`
if [ "$v_use_xref_result" == "Y" ]; then
echo "s" else
echo "n"
fi
when I query the same in sql developer I am getting the result as Y for this query Select Code_Desc From Code_Detail Where Code='UXLOC' and CODE_TYPE='UXRF' the datatype of Code_Desc is varchar
but I am unable to check in if condition. i am getting "n" as result for this script.
can anyone help me how to check it in if condition.
As written, the heredoc syntax in your script doesn't seem to be correct. Try saying:
v_use_xref_result=$(sqlplus -s $UP <<EOF
Select Code_Desc
From Code_Detail
Where Code='UXLOC'
and CODE_TYPE='UXRF'
EOF
)

Resources