2013-05-17 2 views
5

При попытке использовать инструкцию BULK COLLECT я получил ошибку ORA-00947: not enough values.BULK COLLECT в таблицу объектов

Пример сценария:

CREATE OR REPLACE 
TYPE company_t AS OBJECT ( 
    Company   VARCHAR2(30), 
    ClientCnt   INTEGER ); 
/

CREATE OR REPLACE 
TYPE company_set AS TABLE OF company_t;  
/

CREATE OR REPLACE 
FUNCTION piped_set (
    v_DateBegin IN DATE, 
    v_DateEnd IN DATE 
) 
return NUMBER /*company_set pipelined*/ as 
    v_buf company_t := company_t(NULL, NULL); 
    atReport company_set; 
    sql_stmt VARCHAR2(500) := ''; 
begin 

select * BULK COLLECT INTO atReport 
from (
    SELECT 'Descr1', 1 from dual 
    UNION 
    SELECT 'Descr2', 2 from dual) ; 

    return 1; 
end; 

ошибка происходит на линии select * BULK COLLECT INTO atReport.

Прямой PL/SQL работает отлично (так что не нужно упоминать его как решение). Вопрос BULK COLLECT в тип таблицы пользователей.

ответ

9

Ваш company_set представляет собой таблицу объектов, и вы выбираете значения, а не объекты, состоящие из этих значений. Это будет компилировать:

select * BULK COLLECT INTO atReport 
from (
    SELECT company_t('Descr1', 1) from dual 
    UNION 
    SELECT company_t('Descr2', 2) from dual) ; 

... но при запуске будет бросать ORA-22950: cannot ORDER objects without MAP or ORDER method потому что union делает неявное упорядочение для выявления и удаления дубликатов, так что используйте union all вместо:

select * BULK COLLECT INTO atReport 
from (
    SELECT company_t('Descr1', 1) from dual 
    UNION ALL 
    SELECT company_t('Descr2', 2) from dual) ; 
+0

Спасибо, @Alex, код действительно помог! Как продолжение вопроса, можно ли передать результат массовой вставки как результат конвейерной функции? В настоящее время я получаю результат в antReport ant, а затем выполняю «FOR .. LOOP (pipe_row (atReportRow)) END LOOP;». Может быть, эта часть также может быть упрощена? – xacinay

+1

@xacinay - не с 'bulk collect'; вы можете сделать это как цикл курсора вместо этого ('for rec in (select company_t() as comp ...) loop pipe row rec.comp; end loop;' или подобное. Я полагаю, что производительность будет аналогичной. задайте новый вопрос, если вы попробуете это и не можете заставить его работать. –

+0

Именно так оно и работает: 'for x in (select ..) pipe row (company_t (x.Company, x.ClientCnt)))'. Я просто подумал, что это может быть еще проще. Во всяком случае, текущий результат довольно хорош, спасибо! – xacinay

Смежные вопросы