Skip to Main Content
  • Questions
  • Dynamic SQL: Set variable contained in another variable

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question.

Asked: August 09, 2002 - 2:45 pm UTC

Last updated: January 22, 2008 - 7:03 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

Is there a way in PL/SQL that I can set the value of a variable whose name is contained in another variable?

Sort of like the Unix Korn shell's 'eval' function.

i.e. if I have
my_rec table%ROWTYPE;
x varchar2(100) := 'my_rec.col';

Can I set the value of my_rec.col without naming it explicitly?

The reason I ask is that I want to loop thru a PLSQL table containing variable names and 2 parameters which I would then pass to a function which would set the variable i.e.

my_tab(i).var := my_func(my_tab(i).arg1,my_tab(i).arg2)

Here if my_tab(i).var contained x.y, I want the element y in the record x to be actually assigned that value.

Far fetched? Thanks for any insights.

and Tom said...

only if the indirectly referenced variable is a GLOBAL (declared in a package specification and visable to all)


It will not work if the variable is a local variable in a subroutine or if the variable is a package variable in the body.

You can do this:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace package my_pkg
2 as
3 some_variable number := 55;
4 end;
5 /

Package created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace function value_of( p_name in varchar2 ) return varchar2
2 is
3 l_value long;
4 begin
5
6 execute immediate 'begin :x := ' || p_name || '; end;' using out l_value;
7
8 return l_value;
9 end;
10 /

Function created.

ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM>
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_output.put_line( 'the value is ' || value_of( 'my_pkg.some_variable' ) );
the value is 55

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_output.put_line( 'the value is ' || value_of( '2 * my_pkg.some_variable' ) );
the value is 110

PL/SQL procedure successfully completed.




Rating

  (8 ratings)

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

Comments

Clarification

A reader, August 09, 2002 - 3:10 pm UTC

I am not sure I understand.

I want to set the value of my_pkg.some_variable.

i.e. If
x varchar2(100) := 'my_pkg.some_variable'
I want to be able to do "something" to x and have it magically set the value of my_pkg.some_variable


Tom Kyte
August 09, 2002 - 4:36 pm UTC

Fine -- easy enough to do.  Simple variation on a theme here:

ops$tkyte@ORA817DEV.US.ORACLE.COM> create or replace procedure set_value_of( p_name in varchar2, p_newval in varchar2 )
  2  is
  3  begin
  4          execute immediate 'begin ' || p_name || ' := :x; end;' using in p_newval;
  5  end;
  6  /

Procedure created.

ops$tkyte@ORA817DEV.US.ORACLE.COM> 
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec set_value_of( 'my_pkg.some_variable', 1023 );

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> 
ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_output.put_line( 'the value is ' || value_of( 'my_pkg.some_variable' ) );
the value is 1023

PL/SQL procedure successfully completed.

ops$tkyte@ORA817DEV.US.ORACLE.COM> exec dbms_output.put_line( 'the value is ' || value_of( '2 * my_pkg.some_variable' ) );
the value is 2046

PL/SQL procedure successfully completed.



 

Reader

A reader, May 31, 2003 - 9:33 am UTC

Could you tell me why I get ORA- 903

SQL> create or replace function sumup(p_in varchar2)
  2  return number is
  3  l_out number;
  4  begin
  5  execute immediate 'select count(*) into l_out from :x' using in p_in;
  6  return l_out;
  7  end;
  8  /

Function created.

SQL> show errors
No errors.
SQL> select sumup('T_1BYTE') from dual;
select sumup('T_1BYTE') from dual
       *
ERROR at line 1:
ORA-00903: invalid table name
ORA-06512: at "USER.SUMUP", line 5
 The user 'USER' owns the table 'T-1BYTE'.

Thanks 

Tom Kyte
May 31, 2003 - 11:54 am UTC

you cannot bind identifiers.

You can use binds (should use binds in most cases) where ever you could put a character string literal.

for example:


select * from emp where ename = 'KING'

should be:

select * from emp where ename = :bv;

we can use a bind there because we can use a character string. However, we cannot:

select * from :bv where ename = 'KING'

because

select * from 'EMP' where ename = 'KING'

is not valid.

Reader

A reader, May 31, 2003 - 2:18 pm UTC

Is there an alternate way to write function thar computes
count(*) for a table. I think I saw something similar in
this site before. If identifiers can not be parsed, may be
I was wrong

Thanks

Tom Kyte
May 31, 2003 - 2:30 pm UTC

it would be

execute immediate 'select count(*) from ' || p_in into some_variable;





setting and getting privat global variable with dynamic procedure/function

ninoslav, August 01, 2003 - 7:24 am UTC

Hi Tom,
could You show the way we could use dynamic sql in procedure to set package body variable and function to get the value from it.
I have used for procedure:
execute immediate 'begin '
|| p_var_txt
|| ' := :x; end;'
using in p_val;
and
execute immediate 'begin :x := '
|| p_var_txt
|| '; end;'
using out lv_value_txt;
return lv_value_txt;
for function but it doesn't work for package body variable.

Thx


Tom Kyte
August 01, 2003 - 8:03 am UTC

it only works for globally accessible globals - globals in the spec.

the ones in the body are not visible EXCEPT in the body. Just pretend that "execute immediate" is a function call (it is really) -- the dynamically executed sql is taking place in an entirely different scope -- it is not run "in the body", it is called "from the body" -- hence package body variables do not exist.

setting and getting privat global variable with dynamic procedure/function

Ninoslav, August 06, 2003 - 6:03 am UTC

Hi Tom,
thx for Your explanation.
So, to sum up: we can't use dynamic sql for encapsulation data. At least, for now. We have to write explicit proc/function for every variable that we want to use as a privat global variable (package body variable). However, for me, use of dinamic sql for setting package specification variable is very usefull and i'm gonna leave my variables in package specification till something happen about this topic. I know it's not in the spirit of hiding information and advice about enapsulation, but it's much better that write many procedures and functions.
Agree ?

thx
nino

Tom Kyte
August 06, 2003 - 8:23 am UTC



I agree that using and abusing dynamic sql in order to create "really generic stuff" has an extremely high price to be paid in terms of resource utilization in the server....


be careful with this feature -- the old axiom "too much of a good thing" comes into play here.

Dynamic SQL: Set variable contained in another variable

Michel Meurisse, February 18, 2004 - 4:46 am UTC

Wonderull and seems so easy.

Thanks a lot.

dynamic sql

AD, January 22, 2008 - 6:37 pm UTC

Hi Tom,
Could you please suggest how to approach this. I have a table with certain fields. I have to derive a data element using this table, which is calculated as a function of number of fields of tab_a, however the exact expression is stored in a look up table - tab_b.

create table tab_a
(f1 number
,f2 number
)

create table tab_b
(id number
,expr varchar2(200))

INSERT INTO TAB_A ( F1, F2 ) VALUES ( 100, 1); 
INSERT INTO TAB_A ( F1, F2 ) VALUES ( 200, 1); 
INSERT INTO TAB_A ( F1, F2 ) VALUES ( 300, 2); 
INSERT INTO TAB_A ( F1, F2 ) VALUES ( 400, 3);  


INSERT INTO TAB_B ( ID, EXPR ) VALUES (1, 'EXP(-1)F1+F2'); 
INSERT INTO TAB_B ( ID, EXPR ) VALUES ( 2, 'EXP(-1)*F1-F2'); 
INSERT INTO TAB_B ( ID, EXPR ) VALUES ( 3, 'EXP(-1)*F1-10*F2'); 
commit;

SQL> select * from tab_a;

        F1         F2
---------- ----------
       100          1
       200          1
       300          2
       400          3


select ID, expr from tab_b;

        ID
----------
EXPR
--------------------------------------------------------------------------------
         1
EXP(-1)*F1+F2

         2
EXP(-1)*F1-F2

         3
EXP(-1)*F1-10*F2

I would like to get a derived column, which will be added to tab_a, and the logic is:
if tab_a.f2  = tab_b.id then corresponding expression from tab_b will be used.



Many thanks



Tom Kyte
January 22, 2008 - 7:03 pm UTC

please, for the love of whatever, USE A VIEW

do not store some expression to be dynamically invoked.

DO create or replace a view with this.

Instead of stuffing these expressions into a table, create a view that contains these expressions as selected columns.

use a table if you want, but from the table - CREATE A VIEW.

sonu, June 16, 2011 - 5:08 pm UTC

Hi Tom,



v1 varchar2(50) := 'Main';
v2 number := 5;
v3 varcha2(10) := 'Name';

Now v1 := function () -- this function will return 'v2' ||'#'|| 'v3 -- this is nothing but
combination of two variables's name and store them into one variable.

dbms_output.put_line (v1) will print "v2 ||'#'|| v3" but I want to print 5#Name

is it possible?


More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library