sql >> データベース >  >> RDS >> Oracle

oracleFORLOOPはSYS_REFCURSORで繰り返されません

    次の拡張コメントに注意してください:

    おそらく、質問の中心にあるのは、カーソルが何であるかについての誤解です。これはレコードでいっぱいのコンテナではなく、単一のSQLクエリに基づくある時点での結果セットの仕様です。だからあなたが

    open rc for select id from table1;
    

    rcを渡します 呼び出し元に戻ると、データは渡されておらず、準備されたクエリを含むプライベートメモリ領域へのポインタが渡されています。結果をプッシュするのではなく、発信者が結果をプルします。これは、呼び出し元が行をフェッチするために実行するプログラムのようなものです。もう少し開いて別の行を追加することはできません。これはあなたが望んでいたことだと思います。

    プロシージャ内のカーソルでコレクションを使用するには、コレクションタイプを個別のスキーマオブジェクトとして作成する必要があります(もちろん、他のプロシージャでコレクションタイプを再利用できるため、思ったほど制限はありません)。

    タイプを作成できない場合は、使用できるタイプがすでに存在するかどうかを確認してください。

    select owner, type_name
    from   all_coll_types t
    where  t.coll_type = 'TABLE'
    and    t.elem_type_name = 'NUMBER';
    

    例:

    create or replace type number_tt as table of number;
    
    create table table1 (id primary key, currency, t_id) as
        select 10, 'GBP', 'PB1' from dual union all
        select 15, 'GBP', 'RB' from dual union all
        select 20, 'GBP', 'CC' from dual union all
        select 25, 'AUD', 'DC' from dual;
    
    create table table2 (id,country,account) as
        select 10, 'UK', 'PB1' from dual union all
        select 15, 'Wales', 'RB' from dual union all
        select 20, 'SH', 'CC' from dual;
    

    これで、手順は次のようになります。

    create or replace procedure myproc
        ( rc out sys_refcursor)
    as
        l_names number_tt;
    begin
        select id bulk collect into l_names
        from   table1
        where  currency = 'GBP';
    
        open rc for
            select t.id,t.country,t.account from table2 t
            where  t.id member of l_names;
    end myproc;
    

    カーソル出力:

            ID COUNT ACC
    ---------- ----- ---
            10 UK    PB1
            15 Wales RB
            20 SH    CC
    

    i_idを削除しました 使用方法が明確ではなかったため、プロシージャのパラメータ。)

    おそらく、これは実際の問題の簡略版です。現状では、最初のクエリをサブクエリとして使用でき、コレクションは必要ないためです。

    create or replace procedure myproc
        ( rc out sys_refcursor)
    as
    begin
        open rc for
            select t.id,t.country,t.account from table2 t
            where  t.id in
                   ( select id 
                     from   table1
                     where  currency = 'GBP' );
    end myproc;
    

    または、Littlefootが提案したように、参加するだけです:

    create or replace procedure myproc
        ( rc out sys_refcursor)
    as
    begin
        open rc for
            select t2.id, t2.country, t2.account
            from   table1 t1
                   join table2 t2 on t2.id = t1.id
            where  t1.currency = 'GBP';
    end myproc;
    

    しかし、あなたはその答えについて、あなたの要件はコレクション、ループ、いくつかのダクトテープ、2匹の猫と融合ジェネレーターを介してそれを行うことであるように思われたのでそれを行うことができなかったとコメントしました。



    1. SQL-最大値(+ group by)の列を持つ行を選択する方法

    2. データベースオプション/パック使用状況レポート

    3. count(*)SQLステートメントで必要に応じてグループ化しますか?

    4. ユーザーに対してCREATEコマンドが拒否されましたか?