2010-05-13 45 views
16

Estoy intentando crear una función en el paquete que devuelve una tabla. Espero llamar a la función una vez en el paquete, pero ser capaz de volver a utilizar sus múltiples veces de datos. Aunque sé que creo tablas temporales en Oracle, esperaba mantener las cosas SECAS.Crear una función de Oracle que devuelva una tabla

Hasta ahora, esto es lo que tengo:

Cabecera:

CREATE OR REPLACE PACKAGE TEST AS 

    TYPE MEASURE_RECORD IS RECORD (
     L4_ID VARCHAR2(50), 
     L6_ID VARCHAR2(50), 
     L8_ID VARCHAR2(50), 
     YEAR NUMBER, 
     PERIOD NUMBER, 
     VALUE NUMBER 
    ); 

    TYPE MEASURE_TABLE IS TABLE OF MEASURE_RECORD; 

    FUNCTION GET_UPS(
     TIMESPAN_IN IN VARCHAR2 DEFAULT 'MONTLHY', 
     STARTING_DATE_IN DATE, 
     ENDING_DATE_IN DATE 
    ) RETURN MEASURE_TABLE; 

END TEST; 

cuerpo:

CREATE OR REPLACE PACKAGE BODY TEST AS 

    FUNCTION GET_UPS (
    TIMESPAN_IN IN VARCHAR2 DEFAULT 'MONTLHY', 
    STARTING_DATE_IN DATE, 
    ENDING_DATE_IN DATE 
) RETURN MEASURE_TABLE IS 

    T MEASURE_TABLE; 

    BEGIN 

     SELECT ... 
     INTO T 
     FROM ... 

     ; 

    RETURN T; 

    END GET_UPS; 

END TEST; 

La cabecera compila, el cuerpo no. Un mensaje de error es "valores insuficientes", lo que probablemente significa que debería seleccionar MEASURE_RECORD, en lugar de MEASURE_TABLE.

¿Qué me estoy perdiendo?

Respuesta

27

Creo que quieres un pipelined table function.

Algo como esto:

CREATE OR REPLACE PACKAGE test AS 

    TYPE measure_record IS RECORD(
     l4_id VARCHAR2(50), 
     l6_id VARCHAR2(50), 
     l8_id VARCHAR2(50), 
     year NUMBER, 
     period NUMBER, 
     VALUE NUMBER); 

    TYPE measure_table IS TABLE OF measure_record; 

    FUNCTION get_ups(foo NUMBER) 
     RETURN measure_table 
     PIPELINED; 
END; 

CREATE OR REPLACE PACKAGE BODY test AS 

    FUNCTION get_ups(foo number) 
     RETURN measure_table 
     PIPELINED IS 

     rec   measure_record; 

    BEGIN 
     SELECT 'foo', 'bar', 'baz', 2010, 5, 13 
      INTO rec 
      FROM DUAL; 

     -- you would usually have a cursor and a loop here 
     PIPE ROW (rec); 

     RETURN; 
    END get_ups; 
END; 

Por simplicidad le extirpan los parámetros y no puso en práctica un bucle en la función, pero se puede ver el principio.

Uso:

SELECT * 
    FROM table(test.get_ups(0)); 



L4_ID L6_ID L8_ID  YEAR  PERIOD  VALUE 
----- ----- ----- ---------- ---------- ---------- 
foo bar baz   2010   5   13 
1 row selected. 
+0

Supongo que utilizar un cursor requerirá más recursos (es decir, más lento) que usar una tabla temporal. ¿Estoy en lo correcto? Necesito agrupar los resultados de esta función. ¿Eso altera tu recomendación? – craig

+0

Respecto al cursor, sí, creo que no son muy buenos para el rendimiento, por lo que probablemente sería más rápido hacer un BULK COLLECT como Tony mencionó, y luego iterar sobre el conjunto. Dependerá de la cantidad de filas con las que esté trabajando y otras consideraciones de rendimiento. En cuanto a la agrupación de los resultados, no estoy seguro, pero parece probable que una tabla temporal sea más eficiente que una función canalizada en cualquier caso. Sugeriría más investigación (o mejor aún, experimentando). Haría la pregunta en http://asktom.oracle.com. –

+0

Explique abajo. –

3

Para lograr que toda la mesa a la vez podría cambiar el SELECT para:

SELECT ... 
BULK COLLECT INTO T 
FROM ... 

Esto sólo es aconsejable para los resultados que no son excesivamente grandes, ya que todos ellos tiene que ser acumulado en la memoria antes de ser devuelto; de lo contrario, considere la función canalizada como lo sugiere Charles, o devuelva un CURSOR DE REF.

+0

gracias por la comprensión. – craig

0
CREATE OR REPLACE PACKAGE BODY TEST AS 

    FUNCTION GET_UPS(
    TIMESPAN_IN IN VARCHAR2 DEFAULT 'MONTLHY', 
    STARTING_DATE_IN DATE, 
    ENDING_DATE_IN DATE 
    )RETURN MEASURE_TABLE IS 

    T MEASURE_TABLE; 

BEGIN 

    **SELECT MEASURE_RECORD(L4_ID , L6_ID ,L8_ID ,YEAR , 
      PERIOD,VALUE) BULK COLLECT INTO T 
    FROM ...** 

    ; 

    RETURN T; 

    END GET_UPS; 

END TEST; 
+0

¿Cuál es la sintaxis para llamar a esta función? 'select * from TABLE (TEST.GET_UPS (...))'? – craig

Cuestiones relacionadas