Default value for paramteters not passed SQLPlus script - oracle

Is there a way to set default value of paramter in sqlplus script without user input?
For example, I have an SQL script sessions.sql:
SET VERIFY OFF
SET TERMOUT OFF
DEFINE uname = '&1'
COLUMN search_uname new_value search_uname
SELECT CASE WHEN '&uname' = '' THEN '%' ELSE UPPER('&uname') END AS search_uname
FROM dual;
SET TERMOUT ON
SELECT sid, serial, username FROM v$session WHERE username LIKE '&search_uname';
And I want to invoke it from sqlplus like this:
SQL> #sessions
Enter value for 1:
SID SERIAL# USERNAME
---------- ---------- ------------------------------
56 20577 CONTEXT
.....
236 rows selected.
SQL> #sessions ""
SID SERIAL# USERNAME
---------- ---------- ------------------------------
56 20577 CONTEXT
.....
236 rows selected.
SQL> #sessions SDE
SID SERIAL# USERNAME
---------- ---------- ------------------------------
113 56675 SDE
165 64881 SDE
.....
43 rows selected.
SQL>
I can only pass an empty value for parameter when I am asked to enter it, or I am able to pass an empty parameter after script name through "". But this behaviour is very annoying. Some kind of IF DEFINED "&1" will be very usefull.
Do you have any tips or tricks how this should be achieved to apply WHERE conditions in sqlplus script wheter parameter is defined or not without unnecessary user interaction?
Solution
According to the article linked by Martin I modified previous script to be working without aksing for parameter values:
SET VERIFY OFF
SET TERMOUT OFF
column 1 new_value 1
SELECT '' "1" FROM dual WHERE ROWNUM = 0;
define uname = '&1'
SET TERMOUT ON
SELECT sid, serial#, username FROM v$session
WHERE username LIKE UPPER(DECODE('&uname', '', '%', '&uname'));
undefine 1

For those who don't fancy chasing and perusing links that can go away anytime, here's a quick cut'n paste snippet.
set termout on
set serveroutput on
set feedback off
set verify off
-- start
column 1 new_value 1 noprint
select '' "1" from dual where rownum = 0;
define param = &1 "default"
-- end
begin
dbms_output.put_line ( 'Param 1 value is &param' );
end;
/
exit 0
/
Execution:
$ sqlplus -s SCOTT/TIGER#ORCL #a.sql
Param 1 value is default
$ sqlplus -s POSF/POSF#ECMDB #a.sql nondef
Param 1 value is nondef

Please read "On SQL*Plus Defines" for an answer to your question.
Quote:
SQL> COLUMN 1 NEW_VALUE 1
SQL> COLUMN 2 NEW_VALUE 2
SQL> COLUMN 3 NEW_VALUE 3
SQL> COLUMN 4 NEW_VALUE 4
SQL> SELECT '' "1", '' "2", '' "3", '' "4"
2 FROM dual
3 WHERE ROWNUM = 0
4 /
no rows selected
SQL> DEFINE 1
DEFINE 1 = "1" (CHAR)
SQL> DEFINE 2
DEFINE 2 = "2" (CHAR)
SQL> DEFINE 3
DEFINE 3 = "" (CHAR)
SQL> DEFINE 4
DEFINE 4 = "" (CHAR)
SQL>
SQL> REM ...but...
SQL>
SQL> DEFINE 5
SP2-0135: symbol 5 is UNDEFINED

Related

How to give the result of a query in a subtitution variable

sequel from this question
this SQL plus code is working
define a=22;
host powershell.exe echo &a;
22
But if the value from a comes from a query, it doesn't work anymore.
define a=2;
select 22 into a;
host powershell.exe echo &a;
2 instead of 22
I've tried that with a buffer but to no avails
variable buffer varchar2;
select 22 into :buffer from dual;
define a=b;
host powershell.exe echo &a;
:b
You can use the column .. new_value ... syntax. If you still want a bind variable too, as in your previous question, then define and populate that variable however you are now, e.g.:
SQL> variable buffer varchar2(2);
SQL> exec :buffer := '22';
PL/SQL procedure successfully completed.
SQL> print buffer
BUFFER
--------------------------------
22
Then define the column with a new value you can refer to later as a substitution variable:
SQL> column a new_value a
SQL> select :buffer as a from dual;
A
--------------------------------
22
SQL> host powershell.exe echo &a
22
SQL>
You can set termout off and back on around that extra query if you're running this as a script and don't want to see the output.
And you can query anything, it doesn't have to be a bind variable:
select 22 as a from dual;
or
SQL> select sysdate as a from dual;
A
---------
02-JUN-22
SQL> host powershell.exe echo &a
02-JUN-22
SQL>

Encountering an error while using a variable inside CTE in oracle

I want to write the below SQL query(used in sql server) in Oracle SQL developer :
DECLARE #myVAR int;
SET #myVAR = 11;
WITH myCTE
AS (SELECT * FROM abc WHERE HostCount = #myVAR)
SELECT * FROM myCTE
For your case:
DECLARE and INT keywords might be replaced with VAR and NUMBER,
respectively
The variable myVAR is qualified by : instead of #, assignment operator(:=) is used instead of equality sign (=) and nested between BEGIN and END keywords.
The statements on the command
line should be ended by ; and then / .
Code:
SQL> VAR myVAR NUMBER;
SQL> BEGIN :myVAR := 11; END;
2 /
PL/SQL procedure successfully completed
myVAR
---------
11
SQL> WITH myCTE
2 AS (SELECT * FROM abc WHERE HostCount = :myVAR)
3 SELECT * FROM myCTE;
4 /
ID COL1 HOSTCOUNT
---- ------ ----------
.. ... 11
.. ... 11
myVAR
---------
11

How to put a SELECT from Oracle into a bash variable?

I try to save the output of an Oracle SELECT command into a bash variable.
I tried the following lines but it didn't work really well...
ACCESS_SQL=`{
sqlplus << EOF
${USER}/${PASSWORD}#DB
set head off;
set feedback off;
set pagesize 5000;
set linesize 30000;
set serveroutput on;
DECLARE
data varchar(5000);
BEGIN
select ACCESS_ID, PROFILE_ID, START_DATE, END_DATE, PLATFORM, ACCESS_TYPE, PERM_FLAG, ACTIVE_FLAG into data from uam.access_list where USER_ID='${USER_ID}';
dbms_output.put_line(data);
END;
/
exit;
EOF
}`
The error statement I get is :
SQL> SQL> SQL> SQL> SQL> SQL> 2 3 4 5 6 7 select ACCESS_ID, PROFILE_ID, START_DATE, END_DATE, PLATFORM, ACCESS_TYPE, PERM_FLAG, ACTIVE_FLAG into data from uam.access_list where USER_ID='PZ230';
*
ERROR at line 4:
ORA-06550: line 4, column 110:
PL/SQL: ORA-00947: not enough values
ORA-06550: line 4, column 2:
PL/SQL: SQL Statement ignored
I was wondering if using a varchar is the right thing to do...
You don't need to select into a variable and then use dbms_output.put_line to print it out. (Your select into statement won't work anyway, because you can't select multiple columns into a single data variable.)
Instead, do it like this:
data=$(sqlplus -S ${USER}/${PASSWORD} << EOF
set head off
set feedback off
set pagesize 5000
set linesize 30000
select ACCESS_ID, PROFILE_ID, START_DATE, END_DATE, PLATFORM, ACCESS_TYPE, PERM_FLAG, ACTIVE_FLAG from uam.access_list where USER_ID='${USER_ID}';
exit
EOF)
echo "$data"

In oracle 10g, how do I accept user input in a loop?

I have the following pl/sql block:
BEGIN
FOR I IN 1 .. 5
LOOP
INSERT INTO TEST_TABLE VALUES('&slno',SYSDATE);
END LOOP;
END;
When I executed the above block it is taking only one input.
But it is supposed to take 5 input in total.
What is missing in my code? Can any one help me please?
It is a substitution variable - an sql*plus feature - and it doesn't work this way. You have to call undefine &slno or accept slno ... to make it take another input, but these are also sqlplus, not pl/sql commands, so you won't be able to invoke them in a loop,
Probably the only thing you can do here is
INSERT INTO TEST_TABLE VALUES('&slno1',SYSDATE);
INSERT INTO TEST_TABLE VALUES('&slno2',SYSDATE);
INSERT INTO TEST_TABLE VALUES('&slno3',SYSDATE);
INSERT INTO TEST_TABLE VALUES('&slno4',SYSDATE);
INSERT INTO TEST_TABLE VALUES('&slno5',SYSDATE);
update: Fortunately, you can work this around by generaing a list of separate sequential statements accepting independent inputs:
22:38:59 #> conn system/sys#oars_sandbox
Connected.
22:39:01 SYSTEM#oars_sandbox> #s:\test
Enter value for var1: a
Enter value for var2: b
Enter value for var3: c
22:39:06 SYSTEM#oars_sandbox> commit;
22:39:11 SYSTEM#oars_sandbox> select * from test_table;
COL1 COL2
---------- -------------------
a 07.12.2012 22:39:10
b 07.12.2012 22:39:11
c 07.12.2012 22:39:11
22:39:17 SYSTEM#oars_sandbox> get s:\test
1 set echo off
2 set define off
3 set termout off
4 set feedback off
5 set timing off
6 spool s:\123.sql
7 begin
8 for i in 1 .. 3 loop
9 dbms_output.put_line('insert into test_table values(''&var'||i||''', sysdate);');
10 end loop;
11 end;
12 /
13 spool off
14 set define "&"
15 set termout on
16* #s:\123.sql
22:39:24 17 .
22:39:58 SYSTEM#oars_sandbox> get s:\123.sql
1 insert into test_table values('&var1', sysdate);
2 insert into test_table values('&var2', sysdate);
3* insert into test_table values('&var3', sysdate);
22:40:04 SYSTEM#oars_sandbox>
Only after all substitution variables are parsed and substituted(by the client) a final command, query or pl/sq block is sent to the database engine for execution. To that end, it is not possible to repeatedly prompt in a loop. So you might, as an alternative to the #be here now answer, rewrite your pl/sql block as follows:
SQL> set verify off
SQL> declare
2 type T_variables is table of varchar2(11);
3 l_varlist T_variables;
4 begin
5 select v
6 bulk collect into l_varlist -- Assume that there are not so many of them
7 from ( select '&var1' as v from dual union all
8 select '&var2' from dual union all
9 select '&var3' from dual
10 ) ;
11
12 for i in l_varlist.first..l_varlist.last
13 loop
14 insert into test_table(col1, col2)
15 values(l_varlist(i), sysdate);
16 end loop;
17 end;
18
19 /
Enter value for var1: value #1
Enter value for var2: value #2
Enter value for var3: value #3
PL/SQL procedure successfully completed.
SQL> commit;
Commit complete.
SQL> select *
2 from test_table;
COL1 COL2
----------- ---------
value #1 07-DEC-12
value #2 07-DEC-12
value #3 07-DEC-12

Connecting to two different databases and compare the table result using shell script

I have a task of copying the data from one database to another.I don't have privileges to create DB Link.So, I have achieved this task using COPY command in shell script. But now, I need to compare the count of records between the databases. I used to do this manually. But now,I want to automate this.
As per my knowledge, Sqlplus allows me to connect to one database at a time. But I want something like
sqlplus -s un/pwd#sid <<EOF
SELECT count(*) FROM table1 WHERE column1 = 'abc' -- first database
UNION ALL
SELECT count(*) FROM table1 WHERE column1 = 'abc'; -- second database
exit
EOF
Is it possible to omit sqlplus string and add it in the query?
Thanks,
Savitha
You might want to use sqlplus substitution variables to store the query results:
http://docs.oracle.com/cd/B19306_01/server.102/b14357/ch5.htm#sthref1114
These variables are global to a SQL*Plus instance, so they retain their values upon connecting to another database.
Example:
SQL> variable var1 number
SQL> variable var2 number
SQL> conn a/b#ccc
Connected.
SQL> begin
2 select 1111 into :var1 from dual;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> print var1
VAR1
----------
1111
SQL> conn a/b#ddd
Connected.
SQL> print var1
VAR1
----------
1111
SQL> begin
2 select 2222 into :var2 from dual;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> print :var2
VAR2
----------
2222
SQL>
We can also see them like this:
SQL> print :var2 :var1
VAR2
----------
2222
VAR1
----------
1111
SQL>
And use them in PL/SQL:
SQL> set serveroutput on
SQL> declare
2 v1 number := :var1;
3 v2 number := :var2;
4 begin
5 dbms_output.put_line('The difference is: '||to_char((v2-v1)));
6 end;
7 /
The difference is: 1111
PL/SQL procedure successfully completed.
SQL>
you can rush something like this:
A sql file, let's name it tmp.sql:
select count(*) from user_tables;
--SELECT count(*) FROM table1 WHERE column1 = 'abc';
exit;
A sh file, let's name it tmp.sh:
echo pass1 | sqlplus -s user1#sid1 #tmp.sql
echo pass2 | sqlplus -s user2#sid2 #tmp.sql
./tmp.sh would output something like:
Enter password:
COUNT(*)
----------
1717
Enter password:
COUNT(*)
----------
68
(chmod +x tmp.sh)
These scripts can be improved, but this can be a start.
The COPY command is deprecated in SQL*Plus, and has a lot of limitations.
Data pump would be a much more robust way of handling this situation.

Resources