2

パッケージ内に2つの手順があります。ユーザー ID のカンマ区切りのリストを取得するために、1 つのプロシージャを呼び出しています。

VARCHAR結果を変数に格納しています。このカンマ区切りのリストを使用して句の中に入れると、 「例外INがスローされます。ORA-01722:INVALID NUMBER"

これは私の変数がどのように見えるかです

l_userIds VARCHAR2(4000) := null;

これは私が値を割り当てているところです

l_userIds := getUserIds(deptId);  -- this returns a comma separated list

そして、私の2番目のクエリは次のようなものです-

select * from users_Table where user_id in (l_userIds);

このクエリを実行すると、INVALID NUMBERエラーが発生します。

誰かがここで助けてくれますか。

4

4 に答える 4

8

コンマ区切りのリストを本当に返す必要がありますか? 一般に、コレクション型を宣言する方がはるかに優れています

CREATE TYPE num_table
    AS TABLE OF NUMBER;

このコレクションのインスタンスを返す関数を宣言します

CREATE OR REPLACE FUNCTION get_nums
  RETURN num_table
IS
  l_nums num_table := num_table();
BEGIN
  for i in 1 .. 10
  loop
    l_nums.extend;
    l_nums(i) := i*2;
  end loop;
END;

次に、そのコレクションをクエリで使用します

SELECT *
  FROM users_table
 WHERE user_id IN (SELECT * FROM TABLE( l_nums ));

動的 SQL も使用できます (@Sebas が示しています)。ただし、これの欠点は、プロシージャを呼び出すたびに、実行前に再度解析する必要がある新しい SQL ステートメントが生成されることです。また、ライブラリ キャッシュに圧力がかかり、Oracle が他の多くの再利用可能な SQL ステートメントを削除し、他の多くのパフォーマンスの問題を引き起こす可能性があります。

于 2013-08-02T00:41:18.613 に答える
1

問題は、Oracle が渡された VARCHAR2 文字列を一連の数字として解釈しないことです。これは単なる文字列です。

解決策は、クエリ全体を文字列 (VARCHAR2) にしてから実行し、コンテンツを翻訳する必要があることをエンジンが認識できるようにすることです。

DECLARE
    TYPE T_UT IS TABLE OF users_Table%ROWTYPE;
    aVar T_UT;
BEGIN
    EXECUTE IMMEDIATE 'select * from users_Table where user_id in (' || l_userIds || ')' INTO aVar;
...

END;

より複雑で洗練された解決策は、文字列をテーブル TYPE に分割し、それをクエリに直接キャストして使用することです。Tom の考えを見てみましょう。

于 2013-08-02T00:36:55.307 に答える
-1

このソリューションは使用しないでください。

まず、削除したかったのですが、誰かがそのような悪い解決策を見るのは有益かもしれないと思います. このように動的 SQL を使用すると、複数の実行計画が作成されます。IN 句の 1 セットのデータごとに 1 つの実行計画が作成されます。これは、バインディングが使用されておらず、DB の場合、すべてのクエリが異なるためです (SGA は非常に類似した実行でいっぱいになります)。クエリが異なるパラメーターで実行されるたびに、SGA でより多くのメモリが不必要に使用されます)。

動的 SQL をより適切に (バインディング変数を使用して) 使用して別の回答を書きたかったのですが、とにかくJustin Cave の回答が最適です。

REF CURSOR も試してみたいかもしれません (自分でその正確なコードを試したことがないので、少し調整が必要かもしれません):

DECLARE
    deptId                  NUMBER := 2;
    l_userIds               VARCHAR2(2000) := getUserIds(deptId);
    TYPE t_my_ref_cursor IS REF CURSOR;
    c_cursor                t_my_ref_cursor;
    l_row                   users_Table%ROWTYPE;
    l_query                 VARCHAR2(5000);
BEGIN
    l_query := 'SELECT * FROM users_Table WHERE user_id IN ('|| l_userIds ||')';
    OPEN c_cursor FOR l_query;

    FETCH c_cursor INTO l_row;
    WHILE c_cursor%FOUND
    LOOP
        -- do something with your row
        FETCH c_cursor INTO l_row;
    END LOOP;

END;
/

于 2015-09-04T15:23:49.660 に答える