I am trying to pass multiple values about 3000 values, to a BIND variable in Oracle SQL PLUS command prompt like..
SELECT JOB
FROM EMP
WHERE JOB IN :JOB -- bind variable value
I want to see my result, as all the values in EMP
table on column JOB
matching to that variable list has to be fetched out.
As its being production environment I can't create tables only I have grant on SELECT clause.
Need more information on how exactly it get executed when I run the same query from UNIX-SQL PLUS environment.
Will it prompt asking to enter the BIND variables values or can I refer to a file which has values as... :JOB1 := 'MANAGER' :JOB2 := 'CLERK' :JOB3 := 'ACCOUNTANT'
One way to do it in 10g and up is with subquery factoring.
Assume
:JOB
is a comma-separated list of values. The following would work:It's a bit ugly to read, yes, but it works, and Oracle's clever enough to do the parsing of the list of values once, not once per row, which is what you end up with otherwise. What it does under the covers is build a temporary table of the parsed values, which it then can join to the base table.
(I didn't come up with this on my own - original credit goes to an asktom question.)
:JOB
is a bind variable which must be declared and populated before it can be used. The statements below demonstrate how to do that with SQL*Plus.The first question I have to ask is this: where is this list of about 3000 values coming from? If it's coming from another table, then you can write something like the following:
For the rest of this answer, I'll assume it's not in the database anywhere.
In theory it's possible to do what you want. There are various ways to devise a query with a lot of bind variables in it. As an example, I'll write a script to query the
all_objects
data dictionary view using 3000 bind variables. I'm not going to write a SQL*Plus script with 3000 bind variables in it, so instead I wrote a Python script to generate this SQL*Plus script. Here it is:I was then able to run this script, redirect its output to a
.sql
file, and then run that.sql
file in SQL*Plus.You may notice above that I wrote 'In theory it's possible...'. I put the in theory clause there for a good reason. The query appears to be valid, and I don't know of a reason why it shouldn't execute. However, when I ran it on my Oracle instance (XE 11g Beta), I got the following output:
The
ORA-03113
error indicates that the server process crashed.I tried several variations on this:
IN
lists, i.e. writingSELECT ... FROM all_objects WHERE object_id=:X0000 OR object_id=:X0001 OR ...
,all_objects
into a table, and querying that instead.All of the above approaches caused an
ORA-03113
error.Of course, I don't know whether other editions of Oracle will suffer from these crashes (I don't have access to any other editions), but it doesn't bode well.
EDIT: You ask if you can achieve something like
SELECT JOB FROM EMP WHERE JOB IN (:JOB)
. The short answer to that is no. SQL*Plus's usage message for theVARIABLE
command is as follows:All of the above types are single data values, with the exception of
REFCURSOR
, but SQL*Plus still seems to treat that as a single value. I can't find a way to query data returned in aREFCURSOR
this way.So in summary, what you're attempting to achieve is almost certainly impossible. I don't know what your ultimate aim is here, but I don't think you'll be able to do it using a single query in SQL*Plus.
Have a look at the Ugly-Delimited-String-Approach(tm).
That is, bind a string and convert it to a list in SQL. Ugly, that is.
While facing similar problem, I came up with this dirty solution:
Oracle bind variables are a one-to-one relationship, so you'd need one defined for each value you intend to include in the
IN
clause:You need to also be aware that Oracle
IN
only supports a maximum of 1,000 values, or you'll get:The best alternative is to create a table (derived, temporary, actual, or view), and join to it to get the values you want. IE:
Our team just ran into this issue and this query is very clean to pass multiple state values. Each value is separated by comma only. I can pass all 52 states if required: