2012-04-25 14 views
8

私はTable1という名前のテーブルを持っています。それには多くの列があり、そのうちの1つはColumn1です。私は他の列を知らない、時々変わることさえあるかもしれない。 cur_Table1という名前のTable1%rowtypeを返す強い型付きrefカーソル型があります。私はcur_Table1型のoutパラメータを持つSP1という名前のストアドプロシージャを持っています。私はこのストアドプロシージャを、テーブルまたは型自体ではなく、このストアドプロシージャだけを見る別のデータベースから呼び出すことにします。返されるカーソルからColumn1のみを選択するにはどうすればよいですか?私は、レコードまたはカーソルが列を持つように多くの変数をフェッチすることができますが、私は1つの列の存在を知っているので、完全なレコードまたは正しい数の変数を宣言することはできません。Oracle - 参照カーソルから特定の列を選択してください

+0

引数の型を見ることができずに、別のデータベース(またはそのようなデータベースについても)のプロシージャを呼び出す方法を説明してください。 –

+0

私は、 "他の人にSP上で実行許可"をしましたが、テーブルや型パッケージではなく、何も許可しませんでした。そして、それは動作します。 – fejesjoco

+0

ああ、呼び出し側では、もちろん、SPのoutパラメータをsys_refcursorに入れます。 – fejesjoco

答えて

6

これはDBMS_SQLで行うことができますが、それほど美しくはありません。

表とサンプルデータ(COLUMN1数字1は - 10):REFカーソルをオープンし、すべてを選択する手順と

create table table1(column1 number, column2 date, column3 varchar2(1000), column4 clob); 

insert into table1 
select level, sysdate, level, level from dual connect by level <= 10; 
commit; 

パッケージ:

create or replace package test_pkg is 
    type cur_Table1 is ref cursor return table1%rowtype; 
    procedure sp1(p_cursor in out cur_table1); 
end; 
/

create or replace package body test_pkg is 
    procedure sp1(p_cursor in out cur_table1) is 
    begin 
     open p_cursor for select column1, column2, column3, column4 from table1; 
    end; 
end; 
/

参照カーソルからCOLUMN1データを読み取るPL/SQLブロック:

--Basic steps are: call procedure, convert cursor, describe and find columns, 
--then fetch rows and retrieve column values. 
-- 
--Each possible data type for COLUMN1 needs to be added here. 
--Currently only NUMBER is supported. 
declare 
    v_cursor sys_refcursor; 
    v_cursor_number number; 

    v_columns number; 
    v_desc_tab dbms_sql.desc_tab; 
    v_position number; 
    v_typecode number; 
    v_number_value number; 
begin 
    --Call procedure to open cursor 
    test_pkg.sp1(v_cursor); 
    --Convert cursor to DBMS_SQL cursor 
    v_cursor_number := dbms_sql.to_cursor_number(rc => v_cursor); 
    --Get information on the columns 
    dbms_sql.describe_columns(v_cursor_number, v_columns, v_desc_tab); 

    --Loop through all the columns, find COLUMN1 position and type 
    for i in 1 .. v_desc_tab.count loop 
     if v_desc_tab(i).col_name = 'COLUMN1' then 
      v_position := i; 
      v_typecode := v_desc_tab(i).col_type; 

      --Pick COLUMN1 to be selected. 
      if v_typecode = dbms_types.typecode_number then 
       dbms_sql.define_column(v_cursor_number, i, v_number_value); 
      --...repeat for every possible type. 
      end if; 
     end if; 
    end loop; 

    --Fetch all the rows, then get the relevant column value and print it 
    while dbms_sql.fetch_rows(v_cursor_number) > 0 loop 
     if v_typecode = dbms_types.typecode_number then 
      dbms_sql.column_value(v_cursor_number, v_position, v_number_value); 
      dbms_output.put_line('Value: '||v_number_value); 
     --...repeat for every possible type 
     end if; 
    end loop; 
end; 
/
+7

うわー...と私はそれが "カーソルから列1を選択"のような些細なものだろうと思った。 – fejesjoco

1

オプションであるかどうかわかりませんが、探している特定の値を返す関数を作成する方がよい解決策ではありませんか?余分なデータを送信するオーバーヘッドが回避されます。あるいは、両者が知っている既知のフィールドのセットを持つカーソルを定義することもできます。

+0

私はSPのデータベースを支配していないので、サードパーティのクライアントとして他の場所から呼び出す必要があります。 – fejesjoco

3

元の質問を考えれば、ジョーンズの答えは正しいので、私はそのようにマークしておきますが、完全に違ったやり方をしてしまいました。

問題は、私がSP1のデータベースを制御できないということです。サードパーティ製のクライアントとして他の場所から呼び出す必要があります。今ではSPだけでなくカーソルのタイプも見ることができます。私はまだテーブルが表示されていないが、今よりクリーンソリューションがあります:だから私のデータベースに私が行うことができます

type cur_Table1 is ref cursor return Table1%rowtype; 

:私は今、このタイプを参照するアクセス権を付与されている他のデータベースに

今:

mycursor OtherDB.cur_Table1; 
myrecord mycursor%rowtype; 
... 
OtherDB.SP1(mycursor); 
fetch mycursor into myrecord; 
dbms_output.put_line(myrecord.Column1); 

参照してください、私はまだテーブルにアクセスする必要はありません、私はカーソルが表示されます。キーは、魔法の%rowtypeがテーブルだけでなくカーソルでも機能することです。これはsys_refcursorでは機能しませんが、強く型付けされたものでは機能します。このコードが与えられていれば、私は気にする必要はありませんが、私はすべての列やレコードを定義する必要はありません、私は興味を持っている1つの列を指定する必要はありません。私はOracleに関するこのようなOOPの姿勢を本当に愛しています。

関連する問題