2011-07-09 127 views
3

我試圖通過約3000個值的多個值,在Oracle SQL PLUS綁定變量的聲明命令提示符如..在甲骨文綁定變量的多個值

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

我想看到我的結果,必須取出與該變量列表匹配的列JOB上的EMP表中的所有值。


作爲其生產環境我不能創建表只有我對SELECT子句授予。

當我從UNIX-SQL PLUS環境運行相同的查詢時,需要更多關於它如何執行的更多信息。

它會提示要求輸入綁定變量的值或者我可以指具有值... 文件:JOB1:=「MANAGER」 :JOB2:=「祕書」 :作業3:='會計師

回答

4

甲骨文綁定變量是一比一的關係,所以你需要爲每個值來定義你想讓你的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 
+0

作爲其生產環境我不能創建表只有我對SELECT子句授予。 當我從UNIX-SQL PLUS環境運行相同的查詢時,需要了解如何執行它的更多信息。 它會提示要求輸入BIND變量值,還是我可以引用一個文件,其值爲...:JOB1:='MANAGER':JOB2:='CLERK':JOB3:='ACCOUNTANT' – dilipece2001

+0

@ dilipece2001 :如果您的帳戶僅具有SELECT特權,派生表示例應該可以工作。同樣,是的 - 因爲BIND變量是1:1關係,您需要爲每個變量定義值。 –

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在SQL * Plus。

您可能注意到上面我寫'理論上這是可能的......'。理論上我把理論條款放在那裏是有原因的。該查詢似乎是有效的,我不知道它不應該執行的原因。然而,當我跑在我的Oracle實例(XE11克測試版),我得到了以下的輸出:

 
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複製到表中,queryin相反。

以上所有方法都導致ORA-03113錯誤。

當然,我不知道Oracle的其他版本是否會遭受這些崩潰(我無法訪問任何其他版本),但它並不是好兆頭。

編輯:你問你是否可以實現類似SELECT JOB FROM EMP WHERE JOB IN (:JOB)。簡短的回答是否定的。爲VARIABLE命令SQL * Plus中的使用信息如下:

 
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中使用單個查詢。

+0

非常感謝盧克詳細描述它。正如我所提到的那樣,這3000個變量是平面文件,因爲它正在生產環境。我無法創建任何表來保存這3000個值。根據我的知識,我知道BIND變量將保存所有這些3000個值,而不像其他僅保存1000個值的函數。在這裏,我只是感興趣,我們如何將這些值分配到一個特定的BIND變量,並將該變量調用到SELECT子句中,如.. – dilipece2001

+0

SELECT JOB FROM EMP WHERE JOB IN(:JOB)。請建議如何實現這一目標。 – dilipece2001

+0

@ dilipece2001:看到我編輯的答案 –

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的足夠聰明的做值列表的解析一次,每行一次也沒有,這是你到底是什麼否則。它在底下做的是構建一個解析值的臨時表,然後它可以連接到基表。

(我沒有想出這個我自己 - 原來歸功於一個asktom問題。)


:JOB是必須申報並填寫,然後才能使用它綁定變量。以下聲明演示瞭如何使用SQL * Plus進行此操作。

SQL> variable JOB varchar2(4000); 

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

嗨,亞當,我有點困惑如何通過綁定變量可以請你幫我出來...我試着:JOB在(10,20),是這樣做的正確方法?如果不善意建議我。 – dilipece2001

+0

刪除括號。只需'10,20'作爲字符串/ varchar2。 –

+0

嗨,亞當,我從SQL Plus中解僱了。但得到錯誤,我對此很陌生,所以請好好看看這個。提前感謝。 (job_list,instr(job_list,',',1,level)+ 1,instr(job_list,',',1,level + 1)SQL> ed 1 with job_list作爲 2( )作爲工作 4 from(select','||:JOB ||','job_list from dual) 5按級別連接<=長度(: JOB) - 長度(替換(:JOB,',',''))+ 1) 6 * select * from emp where job in(select * from job_list); SQL>:JOB in '10,20'; SP2-0734:未知命令開始「:JOB in'1 ...」 - 忽略行的其餘部分。 – dilipece2001

0

雖然面臨着類似的問題,我想出了這個骯髒的解決方案:

select * from my_table where ',param_1,param_2,param_3,param_4,' LIKE '%,'||my_column||',%' 
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) ;