Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Farhad.

Asked: September 24, 2000 - 8:36 am UTC

Last updated: November 09, 2006 - 2:20 pm UTC

Version: 81.16

Viewed 10K+ times! This question is

You Asked

Hi Tom,
Thanks for the previous answer on updation of values in nested table.Well this time, I want to know the difference between & and && and @ and @@.
Hoping for your prompt reply.

Thanks,
Farhad.

and Tom said...

The && makes it so that SQLPlus will not prompt you each time it sees an &variable in a script. Normally, if you have many occurrences of &variable in a script, sqlplus will prompt you each time for its value. By using &&variable, you have told sqlplus to use the same value for each subsequent occurence of &variable until you would undefine &variable. For example:


ops$tkyte@ORA8I.WORLD> select '&foo' from dual
2 /
Enter value for foo: x

old 1: select '&foo' from dual
new 1: select 'x' from dual

'
-
x

ops$tkyte@ORA8I.WORLD> select '&foo' from dual
2 /
Enter value for foo: y

old 1: select '&foo' from dual
new 1: select 'y' from dual

'
-
y

ops$tkyte@ORA8I.WORLD>
ops$tkyte@ORA8I.WORLD> select '&&bar' from dual
2 /
Enter value for bar: a

old 1: select '&&bar' from dual
new 1: select 'a' from dual

'
-
a

ops$tkyte@ORA8I.WORLD> select '&bar' from dual
2 /
old 1: select '&bar' from dual
new 1: select 'a' from dual

'
-
a

ops$tkyte@ORA8I.WORLD>


Notice how &foo caused us to be prompted 2 times but since I used &&bar in the second example, we did not get prompted later on -- it just reused the value.


The @ and @@ both run scripts however, the @@ runs the script from the directory that the calling script is in. For example, you might be in a directory "/export/home/tom" and you run a script "@/tmp/foo.sql". If foo.sql has a line "@@bar" in it -- that will run the script @/tmp/bar.sql -- we will look for bar in the same directory foo is in. This is commonly used in install scripts to make it so that the user does not have to cd into the directory where the script is to run it.


Rating

  (16 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

How to CD to another Directory when installing with sqlplus scripts...

pasko, April 02, 2003 - 8:31 am UTC

Hi Tom ,

How could i CD to a Sub Directory from my current Directory while installing some packages using sql script which has ' @@ ' constructs in it ..


Example :

my_install.sql has :

@@file1.sql
@@file2.sql
rem i want to move to sub directory now to get another file
@@..\temp_dir\file3.sql
rem but the above apparently doesn't seem to work

is this possible or do i have to always specify a full path ?


Thanks in advance.





Tom Kyte
April 02, 2003 - 9:01 am UTC

the @@ only works on a simple file name -- no relative paths.

Is there a way to make @@ to work with relative path?

Chuan Sat, July 20, 2003 - 12:18 am UTC

Tom

Your answer on @@ is very informative. In your last follow up however you saying that @@ does not work on a relative path?

Is there a way at all to make it work with such path? This is because the root of the relative path in this case may not always be the same, but the subdirectory that is the relative path does.

For example
I am in c:\WorkDir calling

@@c:\InstallDir\Master.sql

Master.sql has..
@@Table.sql
@@View.sql
@@proc\proc1.sql
@@proc\proc2.sql

In this case, @@ will never find proc1.sql and proc2.sql because it is in proc not in InstallDir. I can make it

@@InstallDir\proc\proc1.sql
@@InstallDir\proc\proc1.sql

However the problem is..the root dir. is not always InstallDir, it can be something else like InstallDir2. If I move all the files to InstallDir2, the @InstallDir\proc\proc1.sql becomes immediately invalid.


- is there a another command or a way to make the @@ to work with such relative path? Thanks



pseudo-relative path

finally_got_it, July 29, 2003 - 11:49 am UTC

In unix, I set the SQLPATH environment variable to
include the path to my  master script and the paths to the subdirectories as well.  I find that the @@./subdirectory syntax works when I do this.

I do something like this - 

setenv SQLPATH /auto/bcf/edi/data:/auto/bcf/edi/data/ins

I then run sqlplus from some other directory 

SQL> @crorder 

This executes crorder.sql, which happens to live in /auto/bcf/edi/data.  The script contains several calls like  this

@./ins/insbulklineitem
@./ins/prepacklineitem

which work fine.  If I remove the /auto/bcf/tst/edi/tst/data/ins subdirectory from the SQLPATH, sqlplus reports that it is unable to find insbulklineitem and insprepacklineitem.  It doesn't make a lot of sense to me, but it works which is all I am looking for.  Perhaps you can do something similar in Windows. 

Regarding & and &&

Charlotte, December 08, 2003 - 1:47 pm UTC

Thanks, Tom. This is something I can use every day.

Suppress substitution?

Dennis, January 21, 2004 - 4:31 pm UTC

Is there a way to suppress the substitution output?

So that instead of getting this in a spooled log:

old 9: where owner ='&&1.UTIL')
new 9: where owner ='FINUTIL')
create synonym FINutil.DEMO_TRUNCATE for FINDAILY.DEMO_TRUNCATE;

we could just get the sql statement and not have any old/new lines.

I am calling it by the following method:
@c:\quick_syn.sql FIN

I don't mind just running the spool and getting two nonsense errors, but it's been asked to see if I could eliminate that. I was thinking of using accept and hide, but it wasn't working too well because it stops and wants to accept something that is typed in.

Is there any way to accomplish this?

Thanks,
Dennis

Tom Kyte
January 21, 2004 - 5:59 pm UTC

set verify off


stops the substitution "showing" from happening.

Thanks!

Dennis, January 22, 2004 - 12:51 pm UTC

That was it. Didn't know about the Verify set.

Prompt Variable Fixed Length

denni50, June 02, 2005 - 10:25 am UTC

Hi Tom,

I have Sqlplus Batch Menu that I created to facilitate
user verification and update processes.

On one of the sql scripts that is called from the Batch
Menu Screen users have requested that the prompt variables
be made a fixed length so that they do not, inadvertently
add another digit, the number should be a fixed length(8):

SET TERM ON
Update batch
set status='P'
where batchno between &batch1 and &batch2;
commit;

....is there a way to format the prompts(&batch1 and &batch2) to a fixed length like when using Column Formatting:

Column columnname format a8.

thanks






Tom Kyte
June 02, 2005 - 5:08 pm UTC

need more details -- what do you want to do when

a) input > 8
b) input < 8


(please tell me "fail" for (a), that is the only sensible thing isn't it?)

prompt variable followup

denni50, June 03, 2005 - 8:45 am UTC

Tom...

just want to keep this as simple as possible.

If &batch is < 8 the application will raise an error
stating no such batch number exists. All batch numbers
are 8 digits in length. Users are requesting that the
&batch1 and &batch2 do not allow for more than 8 digits,
whether or not those digits are entered correctly is
subject to user data entry accuracy and verification.

I removed the commit; in the script and now prompt
the user to type in COMMIT; or ROLLBACK; in the event
an incorrect &batch1 and &batch2 are entered.

yesterday a user inadvertently entered &batch2 as 200124451
the intended &batch2 was 20012441....however there does
exist a batch 20012445(which resulted in being incorrectly updated)..the application truncated the last digit since the column datatype(in the batch table) is a number(8).

so all I really need is setting the prompt variable to
a fixed length, along with allowing users to either commit or rollback.

thanks..
ps: did some searching through the SQPlus reference manual
and internet searches and couldn't find anything on substitution variable lengths except for using DEFINE and
that uses a CHAR datatype.





Tom Kyte
June 03, 2005 - 8:51 am UTC

ops$tkyte@ORA10G> @test
Enter x: 12345678
old   2:        if ( length('&x') <> 8 )
new   2:        if ( length('12345678') <> 8 )
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA10G> @test
Enter x: 123456789
old   2:        if ( length('&x') <> 8 )
new   2:        if ( length('123456789') <> 8 )
begin
*
ERROR at line 1:
ORA-20001: You lose
ORA-06512: at line 4
 
 
ops$tkyte@ORA10G> get test
  1  accept x prompt 'Enter x: '
  2  begin
  3     if ( length('&x') <> 8 )
  4     then
  5             raise_application_error( -20001, 'You lose' );
  6     end if;
  7* end;
  8
 

thanks Tom...

denni50, June 03, 2005 - 9:28 am UTC

was hoping to avoid using PL/SQL however in this case
it has it's merits.

:-)



Tom Kyte
June 03, 2005 - 10:01 am UTC

ops$tkyte@ORA10GR2> @test
Enter x: 123
old   1: select case when length('&x') <> 8 then 1/0 end from dual
new   1: select case when length('123') <> 8 then 1/0 end from dual
select case when length('123') <> 8 then 1/0 end from dual
                                          *
ERROR at line 1:
ORA-01476: divisor is equal to zero


there, technically we avoided plsql ;) 

Tom...

denni50, June 03, 2005 - 11:44 am UTC

I decided to do it this way:

SET TERM ON
Update batch
set status='P'
where batchno between substr(&batch1,1,8) and substr(&batch2,1,8);
prompt Please type COMMIT or ROLLBACK;
--commit;

SQL> select substr(&batch1,1,8) from dual;
Enter value for batch1: 200124450000

SUBSTR(2
--------
20012445

this way whatever digits are added after the first 8 are
truncated..they just need to make sure the first 8 digits
are correct...if not then ROLLBACK;

 

Tom Kyte
June 03, 2005 - 12:42 pm UTC

that just sounds wrong to me.

Tom...

denni50, June 03, 2005 - 1:40 pm UTC

This is just a mechanism for users to validate or update
batches before posting data to tables. Before I created
the batch menu screen(see below)...they used to cut
and paste all the sql statements that were used for
verification. In the case I presented here users would actually type out the entire update statement.

When I came on board I asked them if they would like
me to create a SQLPLus Menu were they could select
a number, answer prompts and run the same sql scripts..
they were all..."you can do that???".

so I created this:

set serveroutput on size 1000000 
set echo off verify off trimspool on term on linesize 1000
cl screen
prompt ***************************************************
prompt * Select Batch Verification Processing Option:
prompt *  1.  Verify Client
prompt *  2.  Verify Appealcode
prompt *  3.  Verify Dollars and Count
prompt *  4.  Update Batch Status
prompt *  5.  Verify Batch Flags
prompt *  6.  Verify NULL Acknowledgement
prompt *  7.  Verify NOT LIKE Appealcode
prompt *  8.  Verify NULL GiftType
prompt *  9.  Verify T_Date
prompt * 10.  Verify Year
prompt * 11.  Verify IntCode ATL NATL DECD
prompt * 12.  Verify IntCode 998 UDAD
prompt * 13.  Exit
prompt ***************************************************
accept process prompt ">"
SET TERM OFF
STORE SET saved_settings REPLACE 
SET TERM ON
SET FEEDBACK OFF HEADING OFF 
SPOOL query.sql
select decode(&process,1,'START checkClient',2,'START checkAppealcode',
3,'START checkDollars_Count',4,'START upd_BatchStatus',5,'START check_BatchFlags',
6,'START NullAcknowledgement',7,'START checkAppealcodeNL',
8,'START checkGifttype_Null',9,'START checkT_Date', 10, 'START checkYear_Null',
11,'START checkIntcode',12,'START checkIntcode2',13,'prompt','Please Enter Correct Selection')
from dual;
SPOOL OFF
START saved_settings
START query


in the case I presented here:

**************************************************
* Select Batch Verification Processing Option:
*  1.  Verify Client
*  2.  Verify Appealcode
*  3.  Verify Dollars and Count
*  4.  Update Batch Status
*  5.  Verify Batch Flags
*  6.  Verify NULL Acknowledgement
*  7.  Verify NOT LIKE Appealcode
*  8.  Verify NULL GiftType
*  9.  Verify T_Date
* 10.  Verify Year
* 11.  Verify IntCode ATL NATL DECD
* 12.  Verify IntCode 998 UDAD
* 13.  Exit
**************************************************
>4

START upd_BatchStatus
Enter value for batch1: 20012445
Enter value for batch2: 20012445

1 rows updated.

Please type COMMIT or ROLLBACK
SQL> rollback;

Rollback complete.

SQL> 
 
users are happy...when they're happy, I'm happy!

This is not a situation where a more complex solution
is needed. 







 

Tom Kyte
June 03, 2005 - 5:04 pm UTC

No, the automagical truncation scares me

if "I" typed in 9 digits, "I" would rather you fail the entire thing, not just truncate it.

I probably fat fingered a number *in the middle*, not just added a last digit.

that was my point.

Point well Taken

denni50, June 04, 2005 - 1:41 pm UTC

Tom...

In the context and history of this situation I provided
automation as opposed to manually typing and hard coding
literals,which is just as prone to errors..if not more so.

I agree in an application setting better data entry
controls with user-defined error trapping mechanisms
would be in place..however this is an external preliminary
verification process that checks data before posting(
through the application) to base tables.

In the scenario I presented either one of two things
will occur:

1) number does not exist as entered therefore 0 rows updated.

2) incorrectly entered number does exist, wrong record
got updated(whether error reflects >8 digits truncated or transposed numbers at any point or position between 1-8)

...in that event I empowered users to rollback.

They've been using this Menu system for 2+ years and
it is just recently that one user entered an additional
digit > 8 that resulted in an incorrect update that was
also being automatically committed through the sql script.

Users requested that they be given the choice to either
rollback or commit and that no more than 8 digits be
accepted via the prompt..that's what I gave them.








need help

A reader, October 10, 2005 - 5:11 am UTC

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON

SQL> declare
i NUMBER := 1;
begin
   loop 
    insert into dept values('&deptno','&dname','&loc');
    i := i+1;
    EXIT WHEN i > 2; 
   end loop;
end;
/
Enter value for deptno: 50
Enter value for dname: MANAGEMENT
Enter value for loc: VIRGINIA
old   5:     insert into dept values('&deptno','&dname','&loc');
new   5:     insert into dept values('50','MANAGEMENT','VIRGINIA');

PL/SQL procedure successfully completed.

SQL> select * from dept;

    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 RESEARCH       DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON
        50 MANAGEMENT     VIRGINIA
        50 MANAGEMENT     VIRGINIA

6 rows selected.

My doubt is why is that inputs are not prompted second time in the loop inspite of using &?

thanks
 

Tom Kyte
October 10, 2005 - 8:48 am UTC

sqlplus is the thing that does this substitution - *NOT* plsql.

sqlplus sees "&deptno" and says - ah, they need a deptno, lets ask for it. You gave it 50. It sees &dname , &loc and does the same.

Then sqlplus submitted this VALID plsql block to the server for processing:

declare
i NUMBER := 1;
begin
loop
insert into dept values('50','MANAGEMENT','VIRGINIA');
i := i+1;
EXIT WHEN i > 2;
end loop;
end;
/



PLSQL in the database cannot interact with the enduser - it is way over there on the server running, not interactively on your pc or whatnot.




sqlplus double at (@@) limitation

Jacek Szczepanski, January 13, 2006 - 7:48 am UTC

Thanks for explaining @@ limitation to work only for files but not directories.
Such information should have been a part of @@ documentation in SQL*Plus User's Guide and Reference.
It's also missing in the (otherwise fabulous) Oracle SQL*Plus: The Definitive Guide by Jonathan Gennick.
And Usenet/Google Groups/Orafaq seems to be silent about that.

And if I want to run the script again?

Vinicius Pacheco, November 09, 2006 - 9:26 am UTC

Hi, Tom! Thanks for all unvaluable information in your site.

If I have a script using &&variables (a lot of repetitions) and need to run it again, but with other values, there is a way to clear all variables?



Tom Kyte
November 09, 2006 - 2:20 pm UTC

exit

works very nicely. short of that, you'd have to use undefine variable for each

How to suppress & in a string

Sreekanth, January 24, 2007 - 3:40 am UTC

Hi Tom,
How to suppress the substitution for & if it is part of a string. Like in this example.

SELECT mass_id FROM MASS WHERE RES_STMT = 'C5W&M70&LM7'

The column RES_STMT has the string. But when I do it in SQL*PLUS to check for the existence of that string, i have been asked for substitution.

Your help is appreciated.