11

私の状況:

  • Table1 という名前のテーブルがあります。多くの列があり、そのうちの 1 つが Column1 です。他の列はわかりません。時々変わるかもしれません。
  • Cur_Table1 という名前の、Table1%rowtype を返す厳密に型指定された ref カーソル型があります。
  • タイプ cur_Table1 の out パラメータを持つ SP1 という名前のストアド プロシージャがあります。この SP1 ストアド プロシージャは、このストアド プロシージャのみを参照する別のデータベースから呼び出していますが、テーブルや型自体は参照しません。

返されたカーソルから Column1 のみを選択するにはどうすればよいですか?

レコードまたはカーソルの列と同じ数の変数にフェッチできることはわかっていますが、1 つの列しか存在しないことを知っているため、完全なレコードまたは正しい数の変数を宣言することはできません。

4

3 に答える 3

8

でこれを行うことができますがDBMS_SQL、きれいではありません。

テーブルとサンプル データ (COLUMN1 には 1 から 10 の数字があります):

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

refカーソルから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;
/
于 2012-04-26T06:03:06.863 に答える
4

元の質問を考えると、jonearlesの答えはまだ正しいので、そのようにマークしたままにしますが、最終的にはまったく異なる、はるかに優れたものになりました。

問題は、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 の姿勢が本当に気に入っています。

于 2012-04-27T06:38:44.193 に答える
1

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

于 2012-04-25T19:33:56.583 に答える