查找块中游标或表列的数据类型

Ben*_*Ben 5 oracle plsql oracle9i oracle11g oracle11gr2

是否可以在不使用系统表的情况下找出块内游标或变量的列的数据类型?虽然我知道我可以使用系统表来查找此信息,但速度会慢很多。

就像是,

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;
Run Code Online (Sandbox Code Playgroud)

如果不诉诸 ,我找不到任何方法来做到这一点dbms_sql,这对于我的最终目的来说是矫枉过正的。

但是,甲骨文已经掌握了所有信息。如果我尝试将 a 分配varchar2给 anumber那么它会立即抱怨,以便它知道数据类型是什么。

而且,是的,我知道 Oracle 的版本数量很荒谬,但这就是我们目前拥有的数量……9i 很快就会消亡,取而代之的是 11,但如果我能找到答案,这段代码将立即在 9i 上运行!但我包括了 11 个,因为如果需要的话我可以等待更好的解决方案,

tbo*_*one 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;
Run Code Online (Sandbox Code Playgroud)

现在的问题是,如果有人将光标编码为与另一个表一起使用(我故意选择了一个糟糕的过程名称),您可能会出现错误(在运行时)。就像是:

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;
Run Code Online (Sandbox Code Playgroud)

这也是我更喜欢强类型游标并避免这种情况的原因。

无论如何,对于自描述对象,您可以使用 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;
Run Code Online (Sandbox Code Playgroud)

在这里,您可以根据类型进行程序分支。并使用它:

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

-- output: "You gave me a varchar2"
Run Code Online (Sandbox Code Playgroud)

希望这不是太冗长的回应;)