Звучит так, как будто вам нужен самоописывающий объект. Значение программно найти тип переменной без выбора из какого-либо представления метаданных. Просто спросите объект, кто вы?
В большинстве ситуаций это кажется ненужным, поскольку в большинстве случаев мы уже знаем тип (строго типизированный). Например, параметры процедуры обычно указывают тип (число, 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"
Надеюсь, это был не слишком длинный ответ;)
person
tbone
schedule
10.01.2012
%type
для всех переменных; отсюда следует, что это%rowtype
курсора. В любом случае использование%type
не возвращает тип данных этого конкретного типа. Вы, конечно, правы насчет тестирования; Я бы попытался преобразовать в число и поймать исключение, но мне было интересно, есть ли встроенный способ сделать это, поскольку Oracle знает тип данных, так почему я должен проверять его снова? - person Ben   schedule 09.01.2012