Oracle BIND变量中的多个值的声明

时间:2011-07-09 04:34:36

标签: sql oracle bind-variables

我试图将大约3000个值的多个值传递给Oracle SQL PLUS命令提示符中的BIND变量,如..

SELECT JOB
  FROM EMP 
 WHERE JOB IN :JOB -- bind variable value

我想查看我的结果,因为必须提取与该变量列表匹配的EMPJOB表中的所有值。


由于它是生产环境,我无法创建表,只有SELECT条款才能授予。

当我从UNIX-SQL PLUS环境运行相同的查询时,需要更多关于它是如何执行的信息。

它会提示要求输入BIND变量值,还是可以引用一个值为...的文件? :JOB1:='经理' :JOB2:='CLERK' :JOB3:='ACCOUNTANT'

6 个答案:

答案 0 :(得分:4)

Oracle绑定变量是一对一的关系,因此您需要为要在IN子句中包含的每个值定义一个:

SELECT JOB
  FROM EMP 
 WHERE JOB IN (:JOB1, :JOB2, :JOB3, ..., :JOB3000)

您还需要注意,Oracle IN仅支持最多1,000个值,或者您将获得:

  

ORA-01795:列表中的最大表达式数为1000

最好的选择是创建一个表(派生,临时,实际或视图),并加入它以获得所需的值。 IE:

SELECT a.job
  FROM EMP a
  JOIN (SELECT :JOB1 AS col FROM DUAL
        UNION ALL
        SELECT :JOB2 FROM DUAL
        UNION ALL
        SELECT :JOB3 FROM DUAL
        UNION ALL 
        ...
        UNION ALL 
        SELECT :JOB3000 FROM DUAL) b ON b.col = a.job

答案 1 :(得分:1)

10g及以上的一种方法是使用子查询因子。

假设:JOB是以逗号分隔的值列表。以下方法可行:

with job_list as
(select trim(substr(job_list,
                    instr(job_list, ',', 1, level) + 1,
                    instr(job_list, ',', 1, level + 1)
                      - instr (job_list, ',', 1, level) - 1
                   )
            ) as job
  from (select 
               -- this is so it parses right
               ','|| :JOB ||',' job_list
         from dual)
connect by level <= length(:JOB)
                     - length (replace (:JOB, ',', '') ) + 1
)
select * from emp
 where job in (select * from job_list);

读起来有点难看,是的,但它确实有效,而且Oracle足够聪明,可以对值列表进行一次解析,而不是每行一次,这就是你最终得到的结果。它所做的是构建一个解析值的临时表,然后它可以连接到基表。

(我自己没有提出这个问题 - 最初的功劳归于一个提问题。)


:JOB是一个绑定变量,必须先声明并填​​充它才能使用它。以下语句演示了如何使用SQL * Plus执行此操作。

SQL> variable JOB varchar2(4000);

SQL> exec :JOB := '10, 20';

答案 2 :(得分:0)

查看Ugly-Delimited-String-Approach(tm)

也就是说,绑定一个字符串并将其转换为SQL中的列表。丑陋,就是这样。

答案 3 :(得分:0)

我要问的第一个问题是:这个大约3000个值的列表来自哪里?如果它来自另一个表,那么你可以编写如下内容:

SELECT JOB
  FROM EMP
 WHERE JOB IN (SELECT something FROM some_other_table WHERE ... )

对于本答复的其余部分,我认为它不在任何地方的数据库中。

从理论上讲,你可以做你想做的事。有多种方法可以设计包含大量绑定变量的查询。作为一个例子,我将编写一个脚本来使用3000绑定变量查询all_objects数据字典视图。我不打算在其中编写带有3000个绑定变量的SQL * Plus脚本,所以我写了一个Python脚本来生成这个SQL * Plus脚本。这是:

ns = range(1, 9001, 3) # = 1, 4, 7, ..., 8998

# This gets rid of a lot of lines saying 'PL/SQL procedure successfully completed'.
print "SET FEEDBACK OFF;"
print

# Declare the bind variables and give them values.
for i, n in enumerate(ns):
    print "VARIABLE X%04d NUMBER;" % i
    print "EXEC :X%04d := %d;" % (i, n)
    print

query = "SELECT object_name FROM all_objects WHERE"

# Break up the query into lines to avoid SQL*Plus' limit of 2500 characters per line.
chunk_size = 100
for i in range(0, len(ns), chunk_size):
    query += "OR object_id IN (" + ",".join( ":X%04d" % j for j in range(i, i + chunk_size) ) + ")\n"

query = query.replace("WHEREOR", "WHERE") + ";\n"
print query

然后我能够运行此脚本,将其输出重定向到.sql文件,然后在SQL * Plus中运行该.sql文件。

你可能会注意到我上面写的'理论上它可能......'。我把理论条款放在那里是有充分理由的。查询似乎有效,我不知道它不应该执行的原因。但是,当我在我的Oracle实例(XE 11g Beta)上运行它时,我得到了以下输出:

SQL> @genquery.sql
SELECT object_name FROM all_objects WHERE object_id IN (:X0000,:X0001,:X0002,:X0
003,:X0004,:X0005,:X0006,:X0007,:X0008,:X0009,:X0010,:X0011,:X0012,:X0013,:X0014
,:X0015,:X0016,:X0017,:X0018,:X0019,:X0020,:X0021,:X0022,:X0023,:X0024,:X0025,:X
0026,:X0027,:X0028,:X0029,:X0030,:X0031,:X0032,:X0033,:X0034,:X0035,:X0036,:X003
7,:X0038,:X0039,:X0040,:X0041,:X0042,:X0043,:X0044,:X0045,:X0046,:X0047,:X0048,:
X0049,:X0050,:X0051,:X0052,:X0053,:X0054,:X0055,:X0056,:X0057,:X0058,:X0059,:X00
60,:X0061,:X0062,:X0063,:X0064,:X0065,:X0066,:X0067,:X0068,:X0069,:X0070,:X0071,
:X0072,:X0073,:X0074,:X0075,:X0076,:X0077,:X0078,:X0079,:X0080,:X0081,:X0082,:X0
083,:X0084,:X0085,:X0086,:X0087,:X0088,:X0089,:X0090,:X0091,:X0092,:X0093,:X0094
,:X0095,:X0096,:X0097,:X0098,:X0099)
*
ERROR at line 1:
ORA-03113: end-of-file on communication channel
Process ID: 556
Session ID: 137 Serial number: 29

ORA-03113错误表示服务器进程崩溃。

我尝试了几种变体:

  • 根本不使用绑定变量(即直接输入值)
  • 未使用IN列表,即撰写SELECT ... FROM all_objects WHERE object_id=:X0000 OR object_id=:X0001 OR ...
  • 使用OMG小马的方法,
  • 使用OMG Ponies的方法而不使用绑定变量,
  • 将数据从all_objects复制到表格中,然后再查询。

上述所有方法都导致ORA-03113错误。

当然,我不知道其他版本的Oracle是否会遭受这些崩溃(我无法访问任何其他版本),但它并不是好兆头。

编辑:您问是否可以实现SELECT JOB FROM EMP WHERE JOB IN (:JOB)之类的功能。对此的简短回答是否定的。 SQL * Plus的VARIABLE命令的用法消息如下:

Usage: VAR[IABLE] [  [ NUMBER | CHAR | CHAR (n [CHAR|BYTE]) |
                    VARCHAR2 (n [CHAR|BYTE]) | NCHAR | NCHAR (n) |
                    NVARCHAR2 (n) | CLOB | NCLOB | BLOB | BFILE
                    REFCURSOR | BINARY_FLOAT | BINARY_DOUBLE ] ]

以上所有类型都是单个数据值,但REFCURSOR除外,但SQL * Plus似乎仍然将其视为单个值。我找不到以这种方式查询REFCURSOR返回的数据的方法。

总而言之,你想要实现的目标几乎肯定是不可能的。我不知道你的最终目标是什么,但我认为你不能在SQL * Plus中使用单个查询来完成它。

答案 4 :(得分:0)

在遇到类似问题时,我想出了这个肮脏的解决方案:

select * from my_table where ',param_1,param_2,param_3,param_4,' LIKE '%,'||my_column||',%'

答案 5 :(得分:0)

我们的团队遇到了这个问题,这个查询非常干净,无法传递多个状态值。每个值仅以逗号分隔。如果需要,我可以通过所有52个州:

SELECT county_code,state_code FROM WMS__ASSET_COUNTY_STATE 
WHERE STATE_CODE IN
(SELECT regexp_substr(:bindstateocde, '[^,]+', 1, LEVEL) token
            FROM dual
            CONNECT BY LEVEL <= length(:bindstateocde) - length(REPLACE(:bindstateocde, ',', '')) + 1) ;