How to declare variable and use it in the same Oracle SQL script? - sql

I want to write reusable code and need to declare some variables at the beginning and reuse them in the script, such as:
DEFINE stupidvar = 'stupidvarcontent';
SELECT stupiddata
FROM stupidtable
WHERE stupidcolumn = &stupidvar;
How can I declare a variable and reuse it in statements that follow such as in using it SQLDeveloper.
Attempts
Use a DECLARE section and insert the following SELECT statement in BEGIN and END;. Acces the variable using &stupidvar.
Use the keyword DEFINE and access the variable.
Using the keyword VARIABLE and access the the variable.
But I am getting all kinds of errors during my tries (Unbound variable, Syntax error, Expected SELECT INTO...).

There are a several ways of declaring variables in SQL*Plus scripts.
The first is to use VAR, to declare a bind variable. The mechanism for assigning values to a VAR is with an EXEC call:
SQL> var name varchar2(20)
SQL> exec :name := 'SALES'
PL/SQL procedure successfully completed.
SQL> select * from dept
2 where dname = :name
3 /
DEPTNO DNAME LOC
---------- -------------- -------------
30 SALES CHICAGO
SQL>
A VAR is particularly useful when we want to call a stored procedure which has OUT parameters or a function.
Alternatively we can use substitution variables. These are good for interactive mode:
SQL> accept p_dno prompt "Please enter Department number: " default 10
Please enter Department number: 20
SQL> select ename, sal
2 from emp
3 where deptno = &p_dno
4 /
old 3: where deptno = &p_dno
new 3: where deptno = 20
ENAME SAL
---------- ----------
CLARKE 800
ROBERTSON 2975
RIGBY 3000
KULASH 1100
GASPAROTTO 3000
SQL>
When we're writing a script which calls other scripts it can be useful to DEFine the variables upfront. This snippet runs without prompting me to enter a value:
SQL> def p_dno = 40
SQL> select ename, sal
2 from emp
3 where deptno = &p_dno
4 /
old 3: where deptno = &p_dno
new 3: where deptno = 40
no rows selected
SQL>
Finally there's the anonymous PL/SQL block. As you see, we can still assign values to declared variables interactively:
SQL> set serveroutput on size unlimited
SQL> declare
2 n pls_integer;
3 l_sal number := 3500;
4 l_dno number := &dno;
5 begin
6 select count(*)
7 into n
8 from emp
9 where sal > l_sal
10 and deptno = l_dno;
11 dbms_output.put_line('top earners = '||to_char(n));
12 end;
13 /
Enter value for dno: 10
old 4: l_dno number := &dno;
new 4: l_dno number := 10;
top earners = 1
PL/SQL procedure successfully completed.
SQL>

Try using double quotes if it's a char variable:
DEFINE stupidvar = "'stupidvarcontent'";
or
DEFINE stupidvar = 'stupidvarcontent';
SELECT stupiddata
FROM stupidtable
WHERE stupidcolumn = '&stupidvar'
upd:
SQL*Plus: Release 10.2.0.1.0 - Production on Wed Aug 25 17:13:26 2010
Copyright (c) 1982, 2005, Oracle. All rights reserved.
SQL> conn od/od#etalon
Connected.
SQL> define var = "'FL-208'";
SQL> select code from product where code = &var;
old 1: select code from product where code = &var
new 1: select code from product where code = 'FL-208'
CODE
---------------
FL-208
SQL> define var = 'FL-208';
SQL> select code from product where code = &var;
old 1: select code from product where code = &var
new 1: select code from product where code = FL-208
select code from product where code = FL-208
*
ERROR at line 1:
ORA-06553: PLS-221: 'FL' is not a procedure or is undefined

In PL/SQL v.10
keyword declare is used to declare variable
DECLARE stupidvar varchar(20);
to assign a value you can set it when you declare
DECLARE stupidvar varchar(20) := '12345678';
or to select something into that variable you use INTO statement, however you need to wrap statement in BEGIN and END, also you need to make sure that only single value is returned, and don't forget semicolons.
so the full statement would come out following:
DECLARE stupidvar varchar(20);
BEGIN
SELECT stupid into stupidvar FROM stupiddata CC
WHERE stupidid = 2;
END;
Your variable is only usable within BEGIN and END so if you want to use more than one you will have to do multiple BEGIN END wrappings
DECLARE stupidvar varchar(20);
BEGIN
SELECT stupid into stupidvar FROM stupiddata CC
WHERE stupidid = 2;
DECLARE evenmorestupidvar varchar(20);
BEGIN
SELECT evenmorestupid into evenmorestupidvar FROM evenmorestupiddata CCC
WHERE evenmorestupidid = 42;
INSERT INTO newstupiddata (newstupidcolumn, newevenmorestupidstupidcolumn)
SELECT stupidvar, evenmorestupidvar
FROM dual
END;
END;
Hope this saves you some time

If you want to declare date and then use it in SQL Developer.
DEFINE PROPp_START_DT = TO_DATE('01-SEP-1999')
SELECT *
FROM proposal
WHERE prop_start_dt = &PROPp_START_DT

The question is about to use a variable in a script means to me it will be used in SQL*Plus.
The problem is you missed the quotes and Oracle can not parse the value to number.
SQL> DEFINE num = 2018
SQL> SELECT &num AS your_num FROM dual;
old 1: SELECT &num AS your_num FROM dual
new 1: SELECT 2018 AS your_num FROM dual
YOUR_NUM
----------
2018
Elapsed: 00:00:00.01
This sample is works fine because of automatic type conversion (or whatever it is called).
If you check by typing DEFINE in SQL*Plus, it will shows that num variable is CHAR.
SQL>define
DEFINE NUM = "2018" (CHAR)
It is not a problem in this case, because Oracle can deal with parsing string to number if it would be a valid number.
When the string can not parse to number, than Oracle can not deal with it.
SQL> DEFINE num = 'Doh'
SQL> SELECT &num AS your_num FROM dual;
old 1: SELECT &num AS your_num FROM dual
new 1: SELECT Doh AS your_num FROM dual
SELECT Doh AS your_num FROM dual
*
ERROR at line 1:
ORA-00904: "DOH": invalid identifier
With a quote, so do not force Oracle to parse to number, will be fine:
17:31:00 SQL> SELECT '&num' AS your_num FROM dual;
old 1: SELECT '&num' AS your_num FROM dual
new 1: SELECT 'Doh' AS your_num FROM dual
YOU
---
Doh
So, to answer the original question, it should be do like this sample:
SQL> DEFINE stupidvar = 'X'
SQL>
SQL> SELECT 'print stupidvar:' || '&stupidvar'
2 FROM dual
3 WHERE dummy = '&stupidvar';
old 1: SELECT 'print stupidvar:' || '&stupidvar'
new 1: SELECT 'print stupidvar:' || 'X'
old 3: WHERE dummy = '&stupidvar'
new 3: WHERE dummy = 'X'
'PRINTSTUPIDVAR:'
-----------------
print stupidvar:X
Elapsed: 00:00:00.00
There is an other way to store variable in SQL*Plus by using Query Column Value.
The COL[UMN] has new_value option to store value from query by field name.
SQL> COLUMN stupid_column_name new_value stupid_var noprint
SQL> SELECT dummy || '.log' AS stupid_column_name
2 FROM dual;
Elapsed: 00:00:00.00
SQL> SPOOL &stupid_var.
SQL> SELECT '&stupid_var' FROM DUAL;
old 1: SELECT '&stupid_var' FROM DUAL
new 1: SELECT 'X.log' FROM DUAL
X.LOG
-----
X.log
Elapsed: 00:00:00.00
SQL>SPOOL OFF;
As you can see, X.log value was set into the stupid_var variable, so we can find a X.log file in the current directory has some log in it.

Just want to add Matas' answer.
Maybe it's obvious, but I've searched for a long time to figure out that the variable is accessible only inside the BEGIN-END construction, so if you need to use it in some code later, you need to put this code inside the BEGIN-END block.
Note that these blocks can be nested:
DECLARE x NUMBER;
BEGIN
SELECT PK INTO x FROM table1 WHERE col1 = 'test';
DECLARE y NUMBER;
BEGIN
SELECT PK INTO y FROM table2 WHERE col2 = x;
INSERT INTO table2 (col1, col2)
SELECT y,'text'
FROM dual
WHERE exists(SELECT * FROM table2);
COMMIT;
END;
END;

In Toad I use this works:
declare
num number;
begin
---- use 'select into' works
--select 123 into num from dual;
---- also can use :=
num := 123;
dbms_output.Put_line(num);
end;
Then the value will be print to DBMS Output Window.
Reference to here and here2.

Here's your answer:
DEFINE num := 1; -- The semi-colon is needed for default values.
SELECT &num FROM dual;

You can use a with clause and move filter criteria from a where to a join.
It helps here: Oracle SQL alternative to using DEFINE.
with
mytab as (select 'stupidvarcontent' as myvar from dual)
SELECT
stupiddata
FROM
stupidtable a
inner join
mytab b
on
a.stupidcolumn = b.myvar
WHERE ...;
It works in Oracle 12R2.
It works for one SQL command only.
It is standard ANSI notation.
I'm using it in SQL Developer.

One possible approach, if you just need to specify a parameter once and replicate it in several places, is to do something like this:
SELECT
str_size /* my variable usage */
, LPAD(TRUNC(DBMS_RANDOM.VALUE * POWER(10, str_size)), str_size, '0') rand
FROM
dual /* or any other table, or mixed of joined tables */
CROSS JOIN (SELECT 8 str_size FROM dual); /* my variable declaration */
This code generates a string of 8 random digits.
Notice that I create a kind of alias named str_size that holds the constant 8. It is cross-joined to be used more than once in the query.

Sometimes you need to use a macro variable without asking the user to enter a value. Most often this has to be done with optional script parameters. The following code is fully functional
column 1 noprint new_value 1
select '' "1" from dual where 2!=2;
select nvl('&&1', 'VAH') "1" from dual;
column 1 clear
define 1
Similar code was somehow found in the rdbms/sql directory.

Related

Define, initialise and use variables in SQL developer and SSIS ODBC connection

I am working on a script to be later used in my SSIS ETL, the source DB is oracle and I am using SQL Developer 20.0.2.75 .
I spent so much time declaring 100 variables but it doesn't see to work in SQL developer.
Define & Initialise:
Declare
V1 number;
V2 number;
.
.
.
V100 number;
Begin
Select UDF(params1,param2) into V1 from dual;
Select UDF(params3,param4) into V2 from dual;
...
End;
I was hoping I'd be able to use these variables in my script like :
select columns from table where Col1=:V1 and Col2=:V2
When used "Run Statement" prompts for values, "Run Script" doesn't see to like into Variable statements.
I even tried :
select columns from table where Col1=&&V1 and Col2=&&V2
Now my query doesn't work !
After below responses, I changed my script to :
Variable V1 Number;
Variable V2 Number;
exec select MyFunction(p1,p2) into :V1 from Dual;
/
Select columns from table where col1=:V1 and col2=:V2
It still prompts for value
This is how I defined my function
Create Function MyFunction(m IN Varchar, s IN Number)
Return Number
IS c Number;
select code into c from table where col1=m and col2=s;
Return(c);
End;
Is there anything wrong with the function?
You define variables as per you would in SQL Plus or SQLcl and then run it as a script
Text below
variable x1 number
begin
select 123 into :x1 from dual;
end;
/
print x1
Similar example in SQL Plus (and will work in SQL Dev as well)
SQL> set serverout on
SQL> variable x1 number
SQL> begin
2 select 5 into :x1 from dual;
3 end;
4 /
PL/SQL procedure successfully completed.
SQL> print x1
X1
----------
5
SQL>
SQL> select rownum from dual
2 connect by level <= :x1;
ROWNUM
----------
1
2
3
4
5
SQL>
SQL> begin
2 dbms_output.put_line('X1 is '||:x1);
3 end;
4 /
X1 is 5
PL/SQL procedure successfully completed.
I spent so much time declaring 100 variables
To me, it looks like a wrong approach. OK, declare a few variables, but 100 of them?! Why wouldn't you switch to something easier to maintain. What? A table, for example.
create table params
(var varchar2(20),
value varchar2(20)
);
Pre-populate it with all variables you use (and then just update their values), or just insert rows:
insert into params (var, value) values ('v1', UDF(params1, param2));
insert into params (var, value) values ('v2', UDF(params3, param4));
...
Fetch values through a function:
create or replace function f_params (par_var in varchar2)
return varchar2
is
retval varchar2(20);
begin
select value
into retval
from params
where var = par_var;
return retval;
end;
Use it (in your query) as:
select columns
from table
where Col1 = f_params('v1')
and Col2 = f_params('v2')
If many users use it, consider creating one "master" params table (which contains all the variables) and a global temporary table (which would be populated and used by each of those users).

Stored procedure variable error in PLSQL when declaring variables

Using Oracle 11g when creating the following stored procedure
create or replace PROCEDURE sp_EqualVote(AREA IN NVARCHAR2, DATEOFVOTE IN DATE)
IS
DECLARE test nvarchar(255);
BEGIN
SELECT
AREA,
DATEOFVOTE,
CASE
WHEN (REMAINVOTES = LEAVEVOTES) THEN REMAINVOTES
END AS EqualVote
INTO test
FROM VOTING
WHERE REMAINVOTES = LEAVEVOTES;
END;
END;
I encounter the following error, I'm not quite sure where to go
PLS-00103: Encountered the symbol "DECLARE" when expecting one of the following: begin function pragma procedure subtype type <an identifier> <a double-quoted delimited-identifier> current cursor delete exists prior external language The symbol "begin" was substituted for "DECLARE" to continue.
I'm a university student and not really that familiar with PLSQL. The idea is the stored procedure should display if an an area has equal votes, given the area and date in the procedure then display an equalvotes labeled column with a value of 50
Quite a few mistakes.
you don't need DECLARE within the named PL/SQL procedure
parameters names should differ from column names, so you'd rather use - for example - p_area in nvarchar2, p_dateofvote in date
if you select 3 columns, you have to put them INTO 3 variables - you've declared only one, so either declare two more, or remove AREA and DATEOFOTE from SELECT
what are those parameters used for? Usually, as a part of the WHERE clause - which is not the case in your code
pay attention to number of rows returned by the SELECT statement. If you're selecting into a scalar variable, make sure that it returns only one row
what will you do with TEST variable, once you get its value? Currently, nothing
you've got an END that is a surplus.
Therefore, consider something like this which should at least compile (depending on table description):
SQL> create table voting (area nvarchar2(10),
2 dateofvote date,
3 remainvotes nvarchar2(10),
4 leavevotes nvarchar2(10));
Table created.
SQL> create or replace procedure
2 sp_equalvote(p_area in nvarchar2, p_dateofvote in date)
3 is
4 test nvarchar2(255);
5 begin
6 select
7 case when remainvotes = leavevotes then remainvotes end
8 into test
9 from voting
10 where remainvotes = leavevotes
11 and area = p_area
12 and dateofvote = p_dateofvote;
13 end;
14 /
Procedure created.
SQL>
[EDIT]
After reading the comment, perhaps you'd rather use a function.
Some sample values:
SQL> insert into voting values (1, date '2019-02-20', 100, 15);
1 row created.
SQL> insert into voting values (1, date '2019-03-10', 300, 300);
1 row created.
Function:
SQL> create or replace function
2 sp_equalvote(p_area in nvarchar2, p_dateofvote in date)
3 return nvarchar2
4 is
5 test nvarchar2(255);
6 begin
7 select
8 case when remainvotes = leavevotes then 'draw'
9 else 'not equal'
10 end
11 into test
12 from voting
13 where area = p_area
14 and dateofvote = p_dateofvote;
15
16 return test;
17 end;
18 /
Function created.
SQL>
Testing:
SQL> select * From voting;
AREA DATEOFVOTE REMAINVOTE LEAVEVOTES
---------- ---------- ---------- ----------
1 20.02.2019 100 15
1 10.03.2019 300 300
SQL> select sp_equalvote(1, date '2019-02-20') res from dual;
RES
--------------------
not equal
SQL> select sp_equalvote(1, date '2019-03-10') res from dual;
RES
--------------------
draw
SQL>
DECLARE is not allowed in the body of a PL/SQL procedure. The IS or AS serves the purpose of delimiting where the variable declaration section starts - so your procedure should be
create or replace PROCEDURE sp_EqualVote(AREA IN NVARCHAR2, DATEOFVOTE IN DATE)
IS
test nvarchar(255);
BEGIN
SELECT
AREA,
DATEOFVOTE,
CASE
WHEN (REMAINVOTES = LEAVEVOTES) THEN REMAINVOTES
END AS EqualVote
INTO test
FROM VOTING
WHERE REMAINVOTES = LEAVEVOTES;
END;
You also had an extra END, which I removed.
Best of luck.

PLSQL function wont return salary where name of the employee is passed in as a parameter

Here is my PLSQL function:
Create or Replace FUNCTION getEmpSalary(p_name in VARCHAR)
Return NUMBER IS
l_return_salary;
l_salary;
table_salary NUMBER;
BEGIN
Select salary into table_salary from AlphaCoEmp where p_name = p_name;
return l_return_salary;
END;
/
show errors;
I have built a table that holds the following tuples:
NAME TITLE SALARY
------------------------- --------------------
Wong 91296
Utech 82058
Vega 86858
Weiser 79771
and am trying to write a PLSQL function to return the salary where the name is passed as parameter.
This is how I am passing as parameter: Note: param1 is the name chosen.
exec setEmpSalary(Utech);
I am getting the following error(s):
ERROR at line 1:
ORA-06550: line 1, column 20:
PLS-00201: identifier 'UTECH' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
I am unsure as to how this error is being created and could use some help fixing the error. Thanks for your time.
This is what you might/should have done:
First, a test case:
SQL> create table test
2 (ename varchar2(10),
3 salary number
4 );
Table created.
SQL> insert into test (ename, salary)
2 select 'Wong' , 91296 from dual union
3 select 'Utech', 82058 from dual;
2 rows created.
A function:
note the way I declared the parameter and the return value - both of them use the appropriate datatype of the column they reference
I used the MAX function when selecting the salary. Why? Because, if you pass an invalid employee name, function would return NO_DATA_FOUND error. Another - and probably a better way - is to handle that with the EXCEPTION section, such as
begin
select ...
exception
when no_data_found then return null;
end;
Though, MAX is a quick and dirty solution that saves you from some typing during the testing phase of your code.
SQL> create or replace function get_emp_salary(p_ename in test.ename%type)
2 return test.salary%type
3 is
4 retval test.salary%type;
5 begin
6 select max(t.salary)
7 into retval
8 from test t
9 where t.ename = p_ename;
10
11 return retval;
12 end;
13 /
Function created.
OK, let's see what it does:
SQL> select get_emp_salary('Utech') from dual;
GET_EMP_SALARY('UTECH')
-----------------------
82058
SQL> select get_emp_salary('Littlefoot') from dual;
GET_EMP_SALARY('LITTLEFOOT')
----------------------------
SQL>
Seems to be OK.
In your function, there are 3 local variables. The first two of them are invalidly declared (no datatype). SELECT then selects salary into "table_salary", but you're returning "l_return_salary" which is always NULL - why did you do that?
As of the error you got ("PLS-00201: identifier 'UTECH' must be declared"), it means that you passed the parameter value without single quotes, as you're passing employee name (which is a string).
Also, you're executing setEmpSalary, while the function is get (was it a typo?).
You have problem with your calling code -- UTECH needs to be declared -- or you need to put single quotes around it.
More importantly, the code for the function is wrong, because it confuses a parameter name and a column name.
I think you want:
Create or Replace FUNCTION getEmpSalary (in_p_name in VARCHAR)
Return NUMBER IS
l_return_salary NUMBER;
BEGIN
Select salary into l_return_salary
from AlphaCoEmp ace
where ace.p_name = in_p_name;
return(l_return_salary);
END;
Try
Create or Replace FUNCTION getEmpSalary(p_name in VARCHAR)
Return NUMBER IS
l_return_salary number;
BEGIN
Select salary
into l_return_salary
from AlphaCoEmp
where name = p_name;
return l_return_salary;
exception
when others then
return 0;
END;

Alternate of using NVL with IN clause in Oracle 11g

I have a workplace problem to which I am looking for an easy solution.
I am trying to replicate it in a smaller scenario.
Problem in short
I want to use nvl inside an in clause. Currently I have an input string which consists of a name. It is used in a where clause like below
and column_n = nvl(in_parameter,column_n)
Now I want to pass multiple comma separated values in same input parameter. So if I replace = with in, and transpose the input comma separated string as rows, I cannot use the nvl clause with it.
Problem in Detail
Lets consider an Employee table emp1.
Emp1
+-------+-------+
| empno | ename |
+-------+-------+
| 7839 | KING |
| 7698 | BLAKE |
| 7782 | CLARK |
+-------+-------+
Now this is a simple version of an existing stored procedure
create or replace procedure emp_poc(in_names IN varchar2)
as
cnt integer;
begin
select count(*)
into cnt
from emp1
where
ename = nvl(in_names,ename); --This is one of the condition where we will make the change.
dbms_output.put_line(cnt);
end;
So this will give the count of number of employees passed as Input Parameter. But if we pass null, it will return the whole count of employee becuase of the nvl.
So these procedure calls will render the given outputs.
Procedure Call Output
exec emp_poc('KING') 1
exec emp_poc('JOHN') 0
exec emp_poc(null) 3
Now what I want to achieve is to add another functionality. So exec emp_poc('KING,BLAKE') should give me 2. So I figured a way to split the comma separated string to rows and used that in the procedure.
So if I change the where clause as below to in
create or replace procedure emp_poc2(in_names IN varchar2)
as
cnt integer;
begin
select count(*)
into cnt
from emp1
where
ename in (select trim(regexp_substr(in_names, '[^,]+', 1, level))
from dual
connect by instr(in_names, ',', 1, level - 1) > 0
);
dbms_output.put_line(cnt);
end;
So exec emp_poc2('KING','BLAKE') gives me 2. But passing null will give result as 0. However I want to get 3 like the case with emp_proc
And I cannot use nvl with in as it expect the subquery to return a single value.
1 way I can think of is rebuilding the whole query in a variable, based in input paramteter, and then use execute immediate. But I am using some variables to collect the value and it would be difficult to achieve it with execute immediate.
I am again emphasizing that this is a simple version of a complex procedure where we are capturing many variables and it joins many tables and has multiple AND conditions in where clause.
Any ideas on how to make this work.
This may help you
CREATE OR REPLACE PROCEDURE emp_poc2(in_names IN varchar2)
AS
cnt integer;
BEGIN
SELECT COUNT(*) INTO cnt
FROM emp1
WHERE
in_names IS NULL
OR ename IN (
SELECT TRIM(REGEXP_SUBSTR(in_names, '[^,]+', 1, level))
FROM dual
CONNECT BY INSTR(in_names, ',', 1, level - 1) > 0
);
dbms_output.put_line(cnt);
END;
Other way could be use IF ELSE or UNION ALL
If your real code is much more complex then your code readability might be greatly enhanced by using a proper collection type instead.
In the example below I have created an user defined type str_list_t that is a real collection of strings.
I also use common table expression (CTE) in the sql query to enhance the readability. In this simple example the CTE benefits for readability are not obvious but for all non-trivial queries it's a valuable tool.
Test data
create table emp1(empno number, empname varchar2(10));
insert into emp1 values(5437, 'GATES');
insert into emp1 values(5438, 'JOBS');
insert into emp1 values(5439, 'BEZOS');
insert into emp1 values(5440, 'MUSK');
insert into emp1 values(5441, 'CUBAN');
insert into emp1 values(5442, 'HERJAVEC');
commit;
Supporting data type
create or replace type str_list_t is table of varchar2(4000 byte);
/
Subprogram
create or replace function emp_count(p_emps in str_list_t) return number is
v_count number;
v_is_null_container constant number :=
case
when p_emps is null then 1
else 0
end;
begin
-- you can also test for empty collection (that's different thing than a null collection)
with
-- common table expression (CTE) gives you no benefit in this simple example
emps(empname) as (
select * from table(p_emps)
)
select count(*)
into v_count
from emp1
where v_is_null_container = 1
or empname in (select empname from emps)
;
return v_count;
end;
/
show errors
Example run
SQL> select 2 as expected, emp_count(str_list_t('BALLMER', 'CUBAN', 'JOBS')) as emp_count from dual
union all
select 0, emp_count(str_list_t()) from dual
union all
select 6, emp_count(null) from dual
;
EXPECTED EMP_COUNT
---------- ----------
2 2
0 0
6 6

Arrays in Oracle SQL

Here's a simplified pseudo-code version of what I'd like to be able to do in PL-SQL (Oracle):
DECLARE
mylist as ARRAY
BEGIN
mylist (1) := '1'
mylist (2) := '3'
...
SELECT *
FROM aTable
WHERE aKey IN mylist;
END;
The SELECT should return the matching records for mylist(1), mylist(2) etc. It should be similar to ORing all the values, but of course we don't know in advance how many values we get.
How can I achieve this? I know that PL/SQL has some collection datatypes, but I can't seem to get them to work properly in SQL statements.
Thanks for any ideas.
This is easy to do with the TABLE() function. The one catch is that the array variable must use a type declared in SQL. This is because SELECT uses the SQL engine, so PL/SQL declarations are out of scope.
SQL> create or replace type numbers_nt as table of number
2 /
Type created.
SQL>
SQL> declare
2 l_array numbers_nt;
3 begin
4 l_array := numbers_nt (7521,7566,7654);
5 for r in ( select ename
6 from emp
7 where empno in ( select *
8 from table (l_array)
9 )
10 )
11 loop
12 dbms_output.put_line ( 'employee name = '||r.ename);
13 end loop;
14 end;
15 /
employee name = PADFIELD
employee name = ROBERTSON
employee name = BILLINGTON
PL/SQL procedure successfully completed.
SQL>
A couple of suggestions:
1.) There's a CAST SQL keyword that you can do that might do the job... it makes your collection be treated as if it were a table.
2.) Pipelined functions. Basically a function returns data that looks like a table.
This link summarises the options and has a number of code listings that explain them.
http://www.databasejournal.com/features/oracle/article.php/3352091/CASTing-About-For-a-Solution-Using-CAST-and-Table-Functions-in-PLSQL.htm