宣言

2011-07-09 18 views
3

私は、3000個の値についての複数の値を渡すためにしようとしています。..宣言

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

のようなOracleのSQL PLUSコマンドプロンプトでバインド変数に私は結果を見てみたい、などその変数リストに一致するEMPテーブルの列JOBのすべての値をフェッチする必要があります。


私はテーブルを作成することはできませんが、私はSELECT句を付与しています。

UNIX-SQL PLUS環境から同じクエリを実行したときの実行方法についての詳細が必要です。

は、それがバインド変数の値を入力するように求めるプロンプトが表示されますか私は ...などの値を持つファイルを参照することができます:JOB1:= 'MANAGER' :JOB2:= 'CLERK' :JOB3:= ' ACCOUNTANT」

答えて

4

Oracleのバインド変数は、1対1の関係ですので、あなたが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

私が尋ねなければならない最初の質問は、次のとおりです。このリストはどこから来ていますか?それは別のテーブルから来る場合は、次のような何か書くことができます。

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

この回答の残りのために、私はそれがどこにもデータベースにないと仮定します。

理論的には、あなたが望むことをすることは可能です。その中にたくさんのバインド変数を持つクエリを考案するには、さまざまな方法があります。たとえば、3000のバインド変数を使用してall_objectsデータ・ディクショナリ・ビューを問い合せるスクリプトを作成します。 3000個のバインド変数を持つSQL * Plusスクリプトを書くつもりはないので、代わりにこのSQL * Plusスクリプトを生成するPythonスクリプトを作成しました。ここでは、次のとおりです。

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ファイルを実行することができました。

私は 'と書いてありますが、理論上はです。私は理由のために節に理論でを入れました。クエリは有効であるように見えますが、実行しない理由はわかりません。

 
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エラーは、サーバー・プロセスがクラッシュしたことを示している:私は私のOracleインスタンス(XE 11gのベータ版)でそれを実行したときしかし、私は次の出力を得ました。

私はこの上でいくつかのバリエーションを試してみました:

  • SELECT ... FROM all_objects WHERE object_id=:X0000 OR object_id=:X0001 OR ...書き込みすなわち、INリストを使用していない(すなわち、直接に値を入れて)すべてのバインド変数を使用していない
    • はOMGポニーを使用してアプローチ、
    • バインド変数を使用せずにOMG Poniesのアプローチを使用して、all_objectsのデータをテーブルにコピーし、queryin代わりにそのg。

    上記のすべてのアプローチによって、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

    Lukeに詳しく説明してくれて本当に感謝しています。私が言及したように、3000の変数はフラットファイルにあり、そのプロダクションはenvです。この3000の値を保持するテーブルを作成できませんでした。私の知る限りでは、BIND変数はすべての3000の値を保持し、1000の値しか保持しない他の関数と似ていないことを知っていました。ここで私はちょうど私たちが特定のBIND変数にこれらの値をどのように割り当てるのか興味があり、その変数をSELECT句に呼んでいます。 – dilipece2001

    +0

    JOB IN JOB IN JOB IN(:JOB)からJOBを選択してください。親切にこれを達成するためのアドバイス。 – dilipece2001

    +0

    @ dilipece2001:私の編集された答えを参照 –

    1

    10g以上でそれを行う1つの方法は、サブクエリをファクタリングすることです。

    と仮定します。: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

    こんにちはアダム、私はバインド変数を渡す方法が混乱しています。あなたは私を助けてくれますか...私は試しました:(10,20)の仕事は、それをやる正しい方法ですか?もし私に親切ではないと言ってください。 – dilipece2001

    +0

    かっこを削除します。文字列/ varchar2としてちょうど'10、20 '。 –

    +0

    こんにちはアダム、私はSQL Plusから発射しました。しかし、私はこれに新しいですので、親切にthis.Thanksを見てみましょう。 job_listを1とした 2( )3選択トリム(job_list、job_list、 '、'、1、level)+1、instr(job_list、 '、'、1、level + 1)ジョブをダブルクリックして、ジョブのリストを作成します。 JOB) - length(replace(:JOB、 '、'、 ''))+1) 6 * select * from empジョブは(select * from job_list); SQL>:'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

    私たちのチームは、まさにこの問題に走ったとこのクエリは、複数の状態値を渡すことは非常にきれいです。各値はコンマで区切られています。

    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) ;