2013-05-17 7 views
5

Bei dem Versuch, eine BULK COLLECT Anweisung zu verwenden, habe ich Fehler ORA-00947: not enough values.BULK COLLECT in eine Tabelle von Objekten

Ein Beispielskript:

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; 

Der Fehler tritt bei der Linie select * BULK COLLECT INTO atReport.

Straight PL/SQL funktioniert übrigens gut (also keine Notwendigkeit, es als Lösung zu erwähnen). Die Verwendung von BULK COLLECT in einem Benutzertabellentyp ist die Frage.

Antwort

9

Ihre company_set ist eine Tabelle Objekte, und Sie wählen Werte, keine Objekte aus diesen Werten. Dies kompiliert:

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

... aber bei der Ausführung wird ORA-22950: cannot ORDER objects without MAP or ORDER method werfen, weil die union implizite Ordnung tut Duplikate zu identifizieren und zu entfernen, so verwendet union all statt:

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

Danke, @ Alex, Code wirklich geholfen! Als eine Fortsetzung des Problems ist es möglich, das Ergebnis der Masseneinfügung als Pipeline-Funktionsergebnis zu übergeben? Momentan bekomme ich das Ergebnis in atReport ant und führe dann "FOR .. LOOP (pipe_row (atReportRow)) END LOOP;" aus. Vielleicht kann dieser Teil auch vereinfacht werden? – xacinay

+1

@xacinay - nicht mit 'bulk collect'; Sie könnten es stattdessen als Cursor-Schleife tun ('für rec in (wählen Sie company_t() als comp ...) Loop-Pipe-Zeile rec.comp; end loop;' oder ähnliches. Ich könnte mir vorstellen, dass die Performance ähnlich wäre stelle eine neue Frage, wenn du es versuchst und es nicht funktionieren lässt –

+0

Genau so funktioniert es: 'für x in (select ..) pipe row (company_t (x.Company, x.ClientCnt)))'. Ich habe mich nur gewundert, es kann sogar einfacher sein. Wie auch immer, aktuelles Ergebnis ist ziemlich gut, danke! – xacinay