вторник, 17 мая 2011 г.

Конвейер из табличных (pipelined) функций

    Как-то раньше мне не приходилось сталкиваться с задачей, когда приходилось внутри одной табличной функции запрашивать данные из другой табличной функции в передавать их выше, но в конце концов этот момент настал.
    Мне было необходимо перегрузить табличную функцию, а поскольку алгоритм обработки данных полностью повторял уже существующий я решил воспользоваться вызовом табличной функции.
    Вроде бы всё просто, делай селект типа:
    for foo in (select * from pipelined_function(x))
    loop
        pipe row (r.a, r.b, r.c ...);
    end loop;
    Но мне хотелось больше удобства, не хотел я писать кучу этих имён в pipe row, и начались поиски решения. Слава богу знаний хватило на то, чтобы прийти вот к такому решению:


    Создаём типы:
    create or replace type tr_mixed as object (num number, str varchar2(15));
    create or replace type tt_mixed is table of tr_mixed;
    Создаём pipelined функцию, из которой в последствии будем получать данные:
    create or replace function pipe_func(p_iter number)
    return tt_mixed
    pipelined
    is
    begin
      for l_index in 1 .. p_iter
      loop
        pipe row (tr_mixed(l_index, 'str-' || l_index));
      end loop;
    end pipe_func;
    А теперь создаём pipelined функцию, которая будет запрашивать данные из функции выше:
    create or replace
    function pipe_func_ext
    return tt_mixed
    pipelined
    is
      l_temp_tt tt_mixed;
    begin
      select cast(multiset (select * from table(pipe_func(10))) as tt_mixed)
      into l_temp_tt
      from dual;
      for l_index in l_temp_tt.first .. l_temp_tt.last
      loop
        pipe row (l_temp_tt(l_index));
      end loop;
    end pipe_func_ext;
    Вся магия заключается в псевдофункции MULTISET, которая используется только 4как аргумент псевдофункции CAST.Она позволяет извлечь из базы данных набор значений и тут же преобразовать его в коллекцию нужного типа. Синтаксис у неё такой:
    select cast (multiset (select поле from таблица) as тип_коллекции) from dual
    Если всё равно не понятно, то код:
    select cast(multiset (select * from table(pipe_func(10))) as tt_mixed)
    into l_temp_tt
    from dual;
    можно представить в виде: 
    select tr_number(num, str)
    bulk collect into l_temp_tt
    from table(pipe_func(10));
    Только весь кайф заключается в том, что с multiset, можно писать *
    Проверяем, что всё работает:
    select * from table(pipe_func_ext);

Комментариев нет:

Отправить комментарий