2012-01-23 1 views
3

、あなたは連結を使用IN演算子の値を指定することができます変数を使用して動的クエリにIN句を指定するにはどうすればよいですか? PL/SQLで

v_sql := 'select field1 
from table1 
where field2 in (' || v_list || ')'; 

は、変数を使用して同じことを行うには、それは可能ですか?

v_sql := 'select field1 
from table1 
where field2 in (:v_list)'; 

もしそうなら、どうすればよいですか?

EDIT:Marcinの答えを参照して、結果の表から選択するにはどうすればよいですか?

declare 

cursor c_get_csv_as_tables is 
select in_list(food_list) food_list 
from emp_food 
where emp_type = 'PERM'; 

cursor c_get_food_list (v_food_table varchar2Table)is 
select * 
from v_food_table; 

begin 
    for i in c_get_csv_as_tables loop 
     for j in c_get_food_list(i.food_list) loop 
      dbms_output.put_line(j.element); 
     end loop; 
    end loop; 
end; 

私は次のエラーを取得する:残念ながら、あなたは、このようなリストをバインドすることはできません

ORA-06550: line 10, column 6: 
PL/SQL: ORA-00942: table or view does not exist 
ORA-06550: line 9, column 1: 
PL/SQL: SQL Statement ignored 
ORA-06550: line 15, column 34: 
PLS-00364: loop index variable 'J' use is invalid 
ORA-06550: line 15, column 13: 
PL/SQL: Statement ignored 
+0

[IN句のPL/SQLの使用VARRAY]の可能な重複(http://stackoverflow.com/questions/8476610/pl- sql-use-var-in-in-clause) – Sathya

+0

@Sathya私は理解していない...それはどうですか?私はバインド変数を渡す必要があります。これを行う同様の方法はありますか? – Zesty

+0

私はバインドしたいとは思わなかった。あなたはそのようなバインド変数を使うことはできません。 – Sathya

答えて

7

と同様に、あなたは可変長配列をバインドすることができます(私は@Codo例を取った):

CREATE OR REPLACE TYPE str_tab_type IS VARRAY(10) OF VARCHAR2(200); 
/
DECLARE 
    l_str_tab str_tab_type; 
    l_count NUMBER; 
    v_sql varchar2(3000); 
BEGIN 
    l_str_tab := str_tab_type(); 
    l_str_tab.extend(2); 
    l_str_tab(1) := 'TABLE'; 
    l_str_tab(2) := 'INDEX'; 

    v_sql := 'SELECT COUNT(*) FROM all_objects WHERE object_type IN (SELECT COLUMN_VALUE FROM TABLE(:v_list))'; 

    execute immediate v_sql into l_count using l_str_tab; 

    dbms_output.put_line(l_count); 
END; 
/

UPDATE:最初のコマンドを置き換えることができます。

CREATE OR REPLACE TYPE str_tab_type IS TABLE OF VARCHAR2(200); 
    /

を呼び出してください。

l_str_tab.extend(1); 

これまでに値を追加したとき

+0

ああ、私は今理解しています。しかし、この解決策では、配列の長さを設定するための最大値を知っている必要があります。また、CSV文字列を配列に変換する必要があります。第二はできますが、第一は難しいはずです。 – Zesty

+1

私はVARRAYを元の例で使用したからといって使用しました。 TABLEのVARCHAR2(200)などの別のコレクションを使用できます。 extendメソッドは、追加された各値に対して呼び出すことができます(CSVの変換時) –

2

、しかし、あなたは、表関数を使用することができます。 this

を読むここにあなたのコードに基づいて、使い方の例です:

declare 

cursor c_get_csv_as_tables is 
select in_list(food_list) food_list 
from emp_food 
where emp_type = 'PERM'; 

cursor c_get_food_list (v_food_table varchar2Table)is 
select column_value food 
from TABLE(v_food_table); 

begin 
    for i in c_get_csv_as_tables loop 
     for j in c_get_food_list(i.food_list) loop 
      dbms_output.put_line(j.food); 
     end loop; 
    end loop; 
end; 

あなたがこれを行うことはできませんマルチンの答え@あたりに、しかし、公正がありますとおり、私はここにcolumn_value疑似

+0

ありがとう!他の解決方法があるかどうかを確認し、解決策としてマークします。 – Zesty

+0

このアプローチで問題が発生しました。 「列」名がないため、結果の表から選択するにはどうすればよいですか? – Zesty

1

を使用あなたのクエリが実際に動作する、つまり実行されるように、それに追加するビット。

単純に言えば、表または列にバインド変数を使用することはできません。だけでなく、バ​​インド変数は文字とみなされますので、数字が必要な場合はto_number(:b1)などを使用しなければなりません。

これはクエリが落ちる場所です。文字列を渡すと、Oracleはリスト全体が単一の文字列であるとみなします。したがって、あなたは効果的に走っています:

select field1 
    from table1 
where field2 = v_list 

あなたはこれを別のやり方で行うことはできません。 v_listを動的に作成していると仮定します。つまり、このリストを別に作成するだけです。一連のor条件は、明らかに:-)であり、inと異なることはない。

私が意図していることは、テストされていないものに決して依存しないということです。トムはリンクの中でパフォーマンスの制約があると言いますが、まずはinを使用するよりも速くないという保証はありません。一番良いことは、クエリと彼のトレースを実行して、もしあれば違いがあるかどうかを確認することです。

@Sathyaリンクで
SQL> set serveroutput on 
SQL> 
SQL> declare 
    2 
    3 l_string varchar2(32767); 
    4 l_count number; 
    5 
    6 begin 
    7 
    8  for xx in (select rownum as rnum, a.* 
    9     from user_tables a 
10     where rownum < 20) loop 
11 
12  if xx.rnum = 1 then 
13   l_string := 'table_name = ''' || xx.table_name || ''''; 
14  else 
15   l_string := l_string || ' or table_name = ''' || xx.table_name || ' 
'''; 
16  end if; 
17 
18  end loop; 
19 
20  execute immediate 'select count(*) 
21       from user_tables 
22       where ' || l_string 
23       into l_count 
24        ; 
25 
26  dbms_output.put_line('count is ' || l_count); 
27 
28 end; 
29/
count is 19 

PL/SQL procedure successfully completed. 
+0

偉大な代替ソリューション! – Zesty

2

バインド変数は、 "in"句を含むOracle SQLクエリで使用できます。

10gで動作します。私は他のバージョンについて知らない。

バインド変数は、最大4000文字のvarcharです。

例:コンマで区切られた値のリストを含むバインド変数。

:bindvar = 1,2,3,4,5

select * from mytable 
    where myfield in 
    (
     SELECT regexp_substr(:bindvar,'[^,]+', 1, level) items 
     FROM dual 
     CONNECT BY regexp_substr(:bindvar, '[^,]+', 1, level) is not null 
    );