4

システム テーブルを使用せずにブロック内のカーソルまたは変数の列のデータ型を調べることは可能ですか? システムテーブルを使用してこの情報を見つけることができることは理解していますが、かなり遅くなります。

何かのようなもの、

declare
   my_column_data_type varchar2(30);
begin
  my_column_data_type := all_tables.table_name%type;
  dbms_output.put_line(my_column_data_type);
end;

に頼らずにそれを行う方法を見つけることができませんdbms_sql。これは、最終的な目的にはやり過ぎです。

しかし、オラクルはすでにすべての情報を手に入れています。varchar2aを aに代入しようとすると、numberすぐに文句を言うので、データ型が何であるかがわかります。

そして、はい、オラクルのバージョンの数がばかげていることは知っていますが、それは私たちが現時点で持っている量です... 9iは11を支持して間もなく死にますが、答えを見つけることができれば、このコードはすぐに9iで実行されます! しかし、必要に応じてより良い解決策を待つことができるので、11 を含めました。

4

2 に答える 2

4

dump関数を使用して、結果をこのコードと比較します。

DUMP は、データ型コード、バイト単位の長さ、expr の内部表現を含む VARCHAR2 値を返します。

于 2012-01-09T14:58:11.323 に答える
3

自己記述型のオブジェクトが必要なようです。つまり、メタデータ ビューから選択することなく、変数の型をプログラムで見つけることができます。オブジェクトに聞いてみてください、あなたは何ですか?

ほとんどの場合、型はすでにわかっている (厳密に型指定されている) ため、ほとんどの状況では必要ないように思われます。たとえば、プロシージャのパラメータは通常、型 (数値、varchar2 など) を指定します。ローカル変数は通常、型を指定するか、%type 表記を介してデータベース オブジェクトの型に関連付けます。

任意のクエリに使用できる弱い型指定のカーソル変数など、弱い型指定のオブジェクトが必要または有用な状況がいくつかあります。過度に単純化した例:

create or replace procedure get_data(o_cur OUT SYS_REFCURSOR) as
begin
  OPEN o_cur FOR
  -- without changing parameter, this could select from any table
  select * from emp;
end;

ここでの問題は、誰かがカーソルを別のテーブルで使用するようにコーディングすると、(実行時に) エラーが発生する可能性があることです (意図的にひどいプロシージャ名を選択しました)。何かのようなもの:

declare
  l_cur sys_refcursor;
  l_row dept%rowtype;
begin
  get_data(l_cur);
  -- oops, I thought this was dept data when I coded it, Oracle didn't complain at compile time
  LOOP
    fetch l_cur
    into l_row;
    exit when l_cur%notfound;
    -- do something here
  END LOOP;
  close l_cur;
end;

これが、強く型付けされたカーソルを好み、この状況を避ける理由でもあります。

とにかく、自己記述型オブジェクトの場合は、SYS.ANYDATA 組み込み型を使用できます (同様に、ジェネリック コレクション型の SYS.ANYDATASET)。これは9iで導入されたと思います。たとえば、次のプロシージャは、いくつかのデータを取得し、タイプに基づいてロジックを分岐します。

CREATE OR REPLACE procedure doStuffBasedOnType(i_data in sys.anydata) is
  l_type         SYS.ANYTYPE;
  l_typecode     PLS_INTEGER;
begin
  -- test type
  l_typecode := i_data.GetType (l_type);

  CASE l_typecode
  when Dbms_Types.Typecode_NUMBER then
    -- do something with number
    dbms_output.put_line('You gave me a number');

  when  Dbms_Types.TYPECODE_DATE then
    -- do something with date
    dbms_output.put_line('You gave me a date');

  when  Dbms_Types.TYPECODE_VARCHAR2 then
    -- do something with varchar2
    dbms_output.put_line('You gave me a varchar2');

  else
    -- didn't code for this type...
    dbms_output.put_line('wtf?');

  end case;
end;

ここには、タイプに基づいたプログラムによる分岐があります。そしてそれを使用するには:

declare
  l_data sys.anydata;
begin
  l_data := sys.anydata.convertvarchar2('Heres a string');
  doStuffBasedOnType(l_data);
end;

-- output: "You gave me a varchar2"

返信が長すぎなかったことを願っています;)

于 2012-01-10T12:46:14.633 に答える